-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unified React theming with other CSS-in-JS libraries? #998
Comments
Probably relevant that emotion is planning on changing their theming API completely: #887 I doubt they'll switch to the |
Arh yeah, I see, then it definitely won't use the This problem should maybe be solved as a separate package that works as an adapter between all the major CSS-in-JS theming solutions. |
Imo ity shouldn't be solved that way. Just render two providers with your theme and be done with it, no need to change all CSS-in-JS frameworks: <MUIProvider theme={theme}>
<EmotionProvider theme={theme}>
<App />
</EmotionProvider>
</MUIProvider> |
Ha, you are absolutely right. At first I thought "well, that won't work if you change theme!"... But then I realised I was completely wrong, it will work fine. Thanks! Sorry for the brainfart. I agree with @mxstbr, go ahead and close this issue. 🙂 And have a nice day! 👋 |
@mxstbr's solution looks great! By the way, I wish we could support different backends for |
@Andarist Hi, would you, or someone in the core team, be interested in helping us bringing an emotion backend to Material-UI? |
Could u describe the goals of this? |
@Andarist The goal is to allow people to choose the CSS-in-JS runtime. We shouldn't force the usage of JSS and the bundle size overhead (15 KB) that comes with it if they are already using emotion in their codebase. |
That would be cool, is there any page where it is described how to style material-ui options (from the user perspective)? Including ofc all options available - with described specificity, which styles win over which, how to do theming etc. |
@Andarist What I have in mind only involves our internal API, it should give us more freedom of action. We have the following resources:
Aside the bundle size deduplication, emotion has some additional pros: supports SSR streaming (++ for SEO), is smaller, seems to be faster at runtime server side (depends on the benchmark), has more community adoption, use hashing over index counter that is less error prone. It's a good candidate for being our default runtime. Also, it's to be noted that I want to try a hook API migration on Material-UI side (instead of HOC), I think that it will provides better DX and performance. |
Thanks @oliviertassinari for the links. I'll definitely look into it to see if we could prepare an emotion-flavour of material-ui. |
@Andarist Awesome! I will look into it too. I need to get more familiar with emotion's entrails. |
We're debating on the same thing. @Andarist and @oliviertassinari, do you think feature is implemented these days in Material-UI? |
@gkohen You can use two theme providers to inject the same MUI theme object. Would it work? |
I haven't found time to dig into this (emotion-flavour of Material UI) - really wanted to, but other things got in the way. You can use emotion with Material UI right now, but it costs you two css-in-js to be shipped. |
@Andarist , considering the size of much bigger artifacts such as an image, in our case an extra css-in-js is peanuts. |
Maybe I can answer my own question. How does the following look like:
|
@gkohen https://material-ui.com/guides/interoperability/#themeprovider. I would be eager to find something more elegant! |
@gkohen So, right now, Material-UI documents the following: import React from 'react';
import styled, { ThemeProvider } from 'styled-components';
import NoSsr from '@material-ui/core/NoSsr';
import { createMuiTheme, darken, fade } from '@material-ui/core/styles';
const defaultTheme = createMuiTheme();
const StyledButton = styled.button`
padding: 8px 12px;
border: 1px solid;
cursor: pointer;
outline: none;
border-radius: ${props => props.theme.shape.borderRadius}px;
color: ${props => props.theme.palette.primary.contrastText};
background-color: ${props => props.theme.palette.primary.main};
border-color: ${props => props.theme.palette.primary.main};
transition: ${props => props.theme.transitions.create(['background-color', 'box-shadow'])};
font-family: ${[
'-apple-system',
'BlinkMacSystemFont',
'"Segoe UI"',
'Roboto',
'"Helvetica Neue"',
'Arial',
'sans-serif',
'"Apple Color Emoji"',
'"Segoe UI Emoji"',
'"Segoe UI Symbol"',
].join(',')};
&:hover {
background-color: ${props => darken(props.theme.palette.primary.main, 0.1)};
border-color: ${props => darken(props.theme.palette.primary.main, 0.2)};
}
&:active {
background-color: ${props => darken(props.theme.palette.primary.main, 0.2)};
border-color: ${props => darken(props.theme.palette.primary.main, 0.3)};
}
&:focus {
box-shadow: 0 0 0 0.2rem ${props => fade(props.theme.palette.primary.main, 0.5)};
}
font-size: 18px;
${props => props.theme.breakpoints.up('md')} {
font-size: 16px;
}
`;
function StyledComponentsTheme() {
return (
<NoSsr>
<ThemeProvider theme={defaultTheme}>
<StyledButton>Styled Components</StyledButton>
</ThemeProvider>
</NoSsr>
);
}
export default StyledComponentsTheme; I'm not satisfied with it. I have spent some time to dig into the topic. I have found the following sources to benchmark against:
Leveraging this information, I'm wondering if we couldn't up with the following API. It's meant as a shortcut: import { th } from '@material-ui/core';
const StyledButton = styled.button`
padding: ${th.spacing(1, 1.5)};
border: 1px solid;
background-color: ${th.palette('primary')};
color: ${th.get('palette.primary.main')};
border-radius: ${props => props.theme.shape.borderRadius}px;
transition: ${th.transitions.create(['background-color', 'box-shadow'])};
${th.breakpoints.up('md')} {
font-size: 16px;
} My concern would then be at https://www.npmjs.com/search?q=keywords%3Astyled-components&ranking=popularity. It seems that most people either build internal tools for this problem or don't care. Do they write arrow function everytime they need to? Or do they go with a prop based approach, à la taildwind? Update: looking at Primer, they might be a simpler way: |
@gkohen What do you think of the following instead of the current demo? import React from 'react';
import styled, { ThemeProvider } from 'styled-components';
import NoSsr from '@material-ui/core/NoSsr';
import { createMuiTheme, darken, fade } from '@material-ui/core/styles';
const defaultTheme = createMuiTheme();
const StyledButton = styled.button`
${({ theme }) => `
padding: 8px 12px;
border: 1px solid;
cursor: pointer;
outline: none;
border-radius: ${theme.shape.borderRadius}px;
color: ${theme.palette.primary.contrastText};
background-color: ${theme.palette.primary.main};
border-color: ${theme.palette.primary.main};
transition: ${theme.transitions.create(['background-color', 'box-shadow'])};
font-family: ${[
'-apple-system',
'BlinkMacSystemFont',
'"Segoe UI"',
'Roboto',
'"Helvetica Neue"',
'Arial',
'sans-serif',
'"Apple Color Emoji"',
'"Segoe UI Emoji"',
'"Segoe UI Symbol"',
].join(',')};
&:hover {
background-color: ${darken(theme.palette.primary.main, 0.1)};
border-color: ${darken(theme.palette.primary.main, 0.2)};
}
&:active {
background-color: ${darken(theme.palette.primary.main, 0.2)};
border-color: ${darken(theme.palette.primary.main, 0.3)};
}
&:focus {
box-shadow: 0 0 0 0.2rem ${fade(theme.palette.primary.main, 0.5)};
}
font-size: 18px;
${theme.breakpoints.up('md')} {
font-size: 16px;
}
`}
`;
function StyledComponentsTheme() {
return (
<NoSsr>
<ThemeProvider theme={defaultTheme}>
<StyledButton>Styled Components</StyledButton>
</ThemeProvider>
</NoSsr>
);
}
export default StyledComponentsTheme; |
The proposed change is going live in the documentation in the next release. Related: reddit thread. |
emotion
version: 9.2.12react
version: 16.5.2The problem
Looking at #100 , it looks like it was agreed that Emotion would use the
theming
package to handle all theming in React. I can't really see any trace of this though. So my first question is:Does emotion still use the unified theming approach, or has that been scrapped in favour of a custom solution?
The reason I'm asking, is because I assumed that when using the unified theme approach, the different CSS-in-JS libraries would be able to access the same theme from a single ThemeProvider. It might seem a bit weird to have multiple CSS-in-JS solutions in the same React app, but hear me out.
Motivation
We're using Material-UI for styling, which internally uses JSS as its CSS-in-JS solution. I don't feel the JSS api suits my needs as much as Emotion, so I actually prefer to use Emotion when I make my own custom styles.
However, I can't access the theme provided by Material-UI, because it uses JSS. (I know I can do some hacky stuff like having multiple ThemeProviders, and making sure they stay sync, but this is really an issue where I try to explore the idea of NOT doing that.) So whenever I need to apply styles from the theme, I have to use JSS for styling instead of Emotion.
It becomes a bit confusing in the long run, to use different styling techniques in different places all aorund the code.
The question
So, is there any way we could achieve this, using the unified theming approach? So using the same package as JSS and styled-components, to share themes across CSS-in-JS solutions?
Reproduction
I've made a simple CodeSandbox that demonstrates that emotion cannot read from a theme provided by JSS's
<ThemeProvider />
.The text was updated successfully, but these errors were encountered: