Reputation: 2356
Is there a way to make styled-components
theme adjustable on the fly? For instance, I want the user to be able to change the theme from within the UI and also get theme settings from the API on login.
Currently, my theme looks as follows but I would like to change the hardcoded data for variables that I'd be able to set from UI
import { DefaultTheme } from 'styled-components'
export const theme: DefaultTheme = {
backgroundGradient: 'linear-gradient(to bottom, #f8089c, #e87030)',
palette: {
white: '#fff',
error: '#fa0e15',
pink: '#fe0582',
},
text: {
main: '#f8089c',
white: '#fff',
black: '#000',
},
breakpoints: {
xs: '0px',
sm: '600px',
md: '960px',
lg: '1280px',
xl: '1920px',
},
}
Upvotes: 0
Views: 2019
Reputation: 42160
In order to do this, you want your theme to be stored in a state
somewhere such that it can be updated and those updates will trigger re-renders.
We can use two separate context providers: the styled-components ThemeProvider
and our own context which will provide some sort of callback which is used to update the theme state.
Here's some sample code which should point you in the right direction.
We create a Context
for the theme update function. We give it a default value which logs an error.
const ThemeUpdateContext = createContext(
(theme: DefaultTheme) => console.error("attempted to set theme outside of a ThemeUpdateContext.Provider")
)
We make a custom theme provider that stores the theme in local state. This wraps its children
in providers for both the theme and the update function.
export const MyThemeProvider: React.FC = ({ children }) => {
// store the entire theme as state, using your constant as the initial state
const [myTheme, setMyTheme] = useState(theme);
return (
<ThemeProvider theme={myTheme}>
<ThemeUpdateContext.Provider value={setMyTheme}>
{children}
</ThemeUpdateContext.Provider>
</ThemeProvider>
)
}
We can then use those contexts to make updates from any component inside the MyThemeProvider
. You can, for example, push changes to the theme based on a value retrieved from the API or a cookie from localStorage
.
Here's a very arbitrary example:
const SampleComponent = () => {
const updateTheme = useContext(ThemeUpdateContext);
const currentTheme = useContext(ThemeContext);
return (
<button
onClick={() => updateTheme({
...currentTheme,
text: {
...currentTheme.text,
main: 'blue',
}
})}
>
Make Main Text Blue
</button>
)
}
Upvotes: 1