🔥 Demo First 🔥
Choose a new page theme
When building themable React apps, I have three primary concerns:
- The entire app has a theme.
- A single page can have a theme.
- The page or app theme can change at runtime.
Concerns #1 and #2 are represented on this page right now. By clicking through the links of this blog, you can see that every page has it's own unique set of theme variables, such as background and font colors. Variables optionally override the default app theme.
The venerable CSS-in-JS library styled-components
comes with a <ThemeProvider theme={theme}/>
component which uses React Context to pass it's theme variables to any of it's child components.
In a Next.js app, it's easy to apply this <ThemeProvider />
to all pages by wrapping <Component />
in /pages/_app.js
.
Since all pages are now descendants of <ThemeProvider />
, any component of these pages has easy access to fontColor
and backgroundColor
.
In Next.js, static properties of a page can be accessed in /pages/_app.js
. Let's add a static property to the Page
called pageTheme
Then we'll merge our page theme variables into the default app theme.
The Dynamic Page Theme
In order to change our page theme dynamically, i.e. at the push of a button, we'll need to transcend our static page properties with actual state changes inside /pages/_app.js
.
The overall goal is to maintain state in /pages/_app.js
with a list of pages and their dynamic page overrides. We'll then need to create a function for retrieving and updating the current page's dynamic theme variables. The updateTheme()
function will be passed as a prop to our page which can be used to update the theme!
Since our theme that is passed to ThemeProvider
is now a product of state changes, we can dynamically update any page by calling this.props.updateTheme()
The Random Button
There is a treasure trove of cool color palettes over at colourlovers.com.
Conveniently, there is a library for exactly this purpose on npm!
In order to automatically generate a complete page theme from random color palettes, there is only one hardfast rule: The contrast of the text to background must be high enough that the page is legible.
The basic algorithm is:
- Choose a random colourlovers.com color palette
- Pick the first color in the palette as the background color.
- Find the top two highest contrast colors in the palette against the background color.
- If these contrasts exceed our
CONTRAST_THRESHOLD
, then these colors will be used to update our theme. - If these contrasts DO NOT exceed our
CONTRAST_THRESHOLD
, set the next color in the palette as our background color and try again. - If we've gone through our entire color palette and still haven't found a suitable combination to meet our
CONTRAST_THRESHOLD
, pick a new random palette and try again until we've found something decent.
Usage is as simple as calling generateColorPalette()
and passing it's result to updateTheme()
.
Check out the full demo on CodeSandbox