Creating and Providing Context

A context is created once, outside any component, with createContext(defaultValue) — usually in its own module, so that the provider and every reader import the same object. What it returns holds no data; it is an identity, a key that a provider and a reader agree on.

A component provides a value by rendering the context itself as a component with a value prop, and reads the nearest provided value with useContext. With no provider above it, a reader gets the defaultValue, which is why null is the right default when there is no sensible fallback.

Providing a value, and falling back to the defaultJavaScript
const ThemeContext = createContext('light');   // the fallback value
function Badge() {
  const theme = useContext(ThemeContext);      // reads the nearest provider above
  return <b className={theme}>{theme}</b>;
}
export default function App() {
  return <>
    <Badge />                                  {/* no provider above: renders "light" */}
    <ThemeContext value="dark"><Badge /></ThemeContext>
  </>;
}

Before React 19 7,897 the provider had to be written <ThemeContext.Provider value="dark">. That form still works and you will meet it in every older code base, but <ThemeContext> is now the documented syntax and .Provider is slated for removal. The matching <ThemeContext.Consumer> render-prop component is legacy too.

React walks up from the reader to find the closest provider, so a provider rendered by the same component that reads the context has no effect on that read. Nesting two providers of one context is legal: the inner shadows the outer for its own subtree, which is how a preview pane renders a light card inside a dark application.