React context lets a component share data with the entire tree below it without passing props through every intermediate level. You create a context object, provide a value from a parent, and read that value anywhere below with the useContext Hook. A theme setting is the classic example because it shows all three steps in a few lines, and the same steps work for any shared value, from a color scheme to the signed-in user.
Step 1: Create the context
A context starts as an object returned by createContext. Call it at module scope, outside any component, and export it so other files import the same object. The argument is a fallback value React uses when no provider sits above a reader.
import { createContext } from "react";
export const ThemeContext = createContext("light");The fallback here is the string light. It is only a last resort, and it never changes on its own.
Step 2: Provide the value
Wrap a section of the tree with the context component and pass the current value through its value prop. Every component below that provider can now see the value. The value prop accepts any JavaScript value: a string, a number, an object, or even a function.
import { ThemeContext } from "./theme-context";
export default function App() {
return (
<ThemeContext value="dark">
<Page />
</ThemeContext>
);
}This App provides dark to everything inside Page. In React 19 you can render the context object directly as a provider. In earlier versions, write ThemeContext.Provider instead, with the same value prop.
Step 3: Read the value
Any component below the provider reads the value with the useContext Hook. It takes the context object and returns the value from the nearest provider above. The Hook returns the same value the provider passed, not a copy.
import { useContext } from "react";
import { ThemeContext } from "./theme-context";
function Button({ children }) {
const theme = useContext(ThemeContext);
return <button className={`btn-${theme}`}>{children}</button>;
}This Button renders with the class btn-dark when the provider passes dark. It never receives theme through props, and no component between App and Button has to forward it.
A complete theme example
Combine the three steps in one file to see the full flow. The provider and the reader share one context object, which is what connects them.
import { createContext, useContext } from "react";
const ThemeContext = createContext("light");
function Button() {
const theme = useContext(ThemeContext);
return <button className={`btn-${theme}`}>Save</button>;
}
export default function App() {
return <ThemeContext value="dark"><Button /></ThemeContext>;
}The button appears with dark styling because the provider passes dark. Change the value prop to light and the button switches without touching the Button component.
Nested providers override the value
A provider only affects the tree below it, and the nearest provider wins for its own subtree. You can wrap one section in a different value while the rest of the app keeps the outer value.
function App() {
return (
<ThemeContext value="dark">
<Page />
<ThemeContext value="light">
<Preview />
</ThemeContext>
</ThemeContext>
);
}Page and everything inside it read dark, while Preview reads light. This is how one part of the app can override a shared value without changing it for everyone else.
How updates flow
A context value becomes useful when it changes. If the provider passes a different value, React re-renders every component that reads that context with useContext. See how to update context values from child components to wire the value to state.
When context is the right tool
Context shines when several distant components need the same data, such as a theme, the signed-in user, or a locale. It is not a universal replacement for props.
A prop passed through one or two levels stays clearer than an implicit context. See prop drilling and how to fix it for the cases where context earns its keep.
What context is not
Context is not a state management library and not a global store. It only passes a value down the tree, and that value disappears when the provider unmounts. Treat it as a pipe for shared data, and reach for a reducer or a store when the state logic outgrows a single value.
What to learn next
The default value you pass to createContext matters more than it looks. Continue with safe default values for React context.
Rune AI
Key Insights
- createContext creates a context object that identifies shared data.
- A provider sets the value for every component below it.
- useContext reads the value from the nearest provider above.
- The default value is only a fallback when no provider exists.
- When the value changes, every reader re-renders.
Frequently Asked Questions
What does createContext return?
Do I have to export the context object?
What happens when a component reads context with no provider above?
Conclusion
React context shares data down a tree in three steps: create a context with createContext, provide a value from a parent, and read it with useContext. Use it when several distant components need the same data, and keep props for data that moves through a short, explicit path.
More in this topic
How to Build a Dropdown Menu in React
Build a React dropdown menu with the ARIA menu button pattern. Handle open and close, keyboard arrows, and clicks outside the menu.
How to Animate React Components with Motion
Animate React components with the Motion library. Set up motion, add enter, hover, and exit animations, and respect reduced motion.
Headless UI Components Explained: Logic Without Locked Styling
Understand headless UI components and how libraries like Radix give you unstyled, accessible behavior that you style yourself.