Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to create context for theme with reactjs?

I need to create a context to apply dark or light theme in repositories. There will be no change of themes by button or something like that, I'll just set the theme and that's it

for now, I have context like this

import { createContext } from "react";
import { light } from './themes';

export const ThemeContext = createContext(light);

export default ThemeContext;

and my app

import { light, dark } from './themes';


<ThemeContext.Provider value={light}> // or dark, depending on the project
   <App />   
 </ThemeContext.Provider> 
);

that way is not working, how can I apply the theme?

like image 545
ryan Most Avatar asked Oct 31 '25 13:10

ryan Most


1 Answers

You've created a provider which makes its value available to every child in the tree. But, any child that wants to use that value needs to consume it.

The patterns for how to consume the context are different for class components VS. function components but the basic principle is the same: you need tell your child component how to get the theme value from the context.

Consuming Context from a function component

For function components, the simplest way is with the useContext hook (example copied straight from the hooks docs):

function ThemedButton() {
  const theme = useContext(ThemeContext);
  
  return (
    <button style={{ background: theme.background, color: theme.foreground }}>
      I am styled by theme context!
    </button>
  );
}

A helpful pattern with a custom hook

The above works, but there's a really nice pattern where you can wrap the consumer in a custom hook which you'd call something like useTheme (I first saw this pattern here).

// Step 1
const ThemeContext = React.createContext(undefined)

// Step 2
function ThemeProvider({children}) {
  return (
    <ThemeContext.Provider value={light}>
      {children}
    </ThemeContext.Provider>
  )
}

// Step 3
function useTheme() {
  const context = React.useContext(ThemeContext)
  
  if (context === undefined) {
    throw new Error('useTheme must be used within a ThemeProvider')
  }
  return context
}

export {ThemeProvider, useTheme}

Step 1 - Creates the context. You've already done this in your example.

Step 2 - Creates the provider. You've used a provider in "my app".

Step 3 - This is what's new. It creates a custom hook that checks that the provider is accessible (throwing an error if not) and then returns the value from the provider.

You then use the hook like this:

function ThemedButton() {
  const theme = useTheme()
  
  return <Text color={theme.textColor}>Some text</Text>
}

There are a few benefits to this pattern:

  1. You only need to import the hook, useTheme, in the components that consume the theme. If you use useContext directly, you need to import the context and the useContext hook.
  2. The throw new Error('...') line will warn you if you accidentally try to use useTheme somewhere in the component tree that doesn't have access to the provider.

Consuming Context with a class component

The examples with class components are a little long and more nuanced, so I'll recommend using the docs for the details of how to do that. But, one approach is like this:

<ThemeContext.Consumer>
  {value => <ThemedButton theme={value} />
</ThemeContext.Consumer>
like image 69
Tyler Auer Avatar answered Nov 02 '25 02:11

Tyler Auer