I have been working on a React web application with a dynamic theme using the emotion-theming library. So a user can switch between environments and each environment has its own theme. I have created my own CustomThemeProvider which I use to dynamicly change the theme. Below is the code.
export interface CustomThemeContextValue {
customTheme?: Theme;
setCustomTheme: (theme: Theme) => void;
};
const CustomThemeContext = React.createContext<CustomThemeContextValue>({
customTheme: undefined,
setCustomTheme: (theme) => { }
});
interface CustomThemeProviderProps {
}
export const CustomThemeProvider: FC<CustomThemeProviderProps> = (props) => {
const [customTheme, setCustomTheme] = useState<Theme>(theme);
const context: CustomThemeContextValue = React.useMemo(() => ({
customTheme,
setCustomTheme
}), [customTheme, setCustomTheme]);
return (
<CustomThemeContext.Provider value={context}>
<ThemeProvider theme={customTheme} {...props} />
</CustomThemeContext.Provider>
);
};
export const useCustomTheme = () => {
const context = React.useContext(CustomThemeContext);
if (!context) {
throw new Error('useCustomTheme must be used within a CustomThemeProvider');
}
return context;
};
The provider is implemented in the root like so
const Root = () => {
return (
<StrictMode>
<CustomThemeProvider>
<Normalize />
<Global styles={globalStyle} />
<App />
</CustomThemeProvider>
</StrictMode>
);
};
So this code is working, I can get the theme within a function component using the emotion useTheme hook like below:
const theme: Theme = useTheme();
But the question is how to get the theme out of the emotion ThemeProvider and use it in certain situations. Is it possibe to use it in a context like
export const style: Interpolation = {
cssProp: value
};
Or is it usable in a context like below where styled.button is from emotion/styled.
const Button: FC<HTMLProps<HTMLButtonElement> & ButtonProps> = styled.button([]);
and is it usable in the emotion/core method css() like below
const style = css({
cssProp: value
});
I find it very hard to find answers to these questions using google so I hope somebody here can help me out.
So after a while I have finally found an answer to my own question and I like to share it with everyone as it is very hard to find. so here it is.
Instead of Interpolation you can use InterpolationWithTheme like below:
import { InterpolationWithTheme } from '@emotion/core';
export const style: InterpolationWithTheme<Theme> = (theme) => ({
cssProp: theme.value
});
This way you can get the theme out of the ThemeProvider.
With the styled componenents you can implement it like below:
const Button: FC<HTMLProps<HTMLButtonElement> & ButtonProps>
= styled.button(({ theme }: any) => ([
{
cssProp: theme.value
}
]);
And finally when you want to use the css() with the themeProvider you have to replace it with the InterpolationWithTheme to make it work just like in the first example of this answer.
These answers have been found by a combination of looking in the emotionjs docs and inspecting the emotionjs types/interfaces.