Skip to content

Solid.js Context — Shared State Across Components

DodaTech Updated 2026-06-28 3 min read

In this tutorial, you will learn about Solid.js Context. We cover key concepts, practical examples, and best practices to help you master this topic.

Learn Solid.js Context: create context providers, consume context with useContext, and share reactive state across the component tree without prop drilling.

In this lesson, you'll use createContext and useContext to share signals, functions, and configuration across deeply nested components.

What You'll Learn

How to create context, provide values, consume context in child components, and organize context for large applications.

Why It Matters

Context eliminates prop drilling—passing props through multiple intermediate components. It's essential for shared state like themes, auth, and user preferences.

Real-World Use

Doda Browser uses context for theme preferences, user settings, and active tab state across the component tree.

flowchart TD
    A[Provider] --> B[Component A]
    A --> C[Component B]
    C --> D[Component C]
    C --> E[Component D]
    B --> F[Component E]
    style A fill:#2c4f7c,color:#fff

Creating Context

import { createContext, useContext } from "solid-js";

const ThemeContext = createContext("light");

function ThemeProvider(props) {
  const [theme, setTheme] = createSignal(props.default || "light");

  return (
    <ThemeContext.Provider value={[theme, setTheme]}>
      {props.children}
    </ThemeContext.Provider>
  );
}

Consuming Context

function ThemedButton() {
  const [theme, setTheme] = useContext(ThemeContext);

  return (
    <button
      onClick={() => setTheme(theme() === "light" ? "dark" : "light")}
      class={`btn-${theme()}`}
    >
      Toggle Theme
    </button>
  );
}

Provider Pattern

function App() {
  return (
    <ThemeProvider default="dark">
      <Header />
      <MainContent />
      <Footer />
    </ThemeProvider>
  );
}

Context with Signals

const AuthContext = createContext();

function AuthProvider(props) {
  const [user, setUser] = createSignal(null);
  const [loading, setLoading] = createSignal(true);

  const login = async (email, password) => {
    setLoading(true);
    const userData = await api.login(email, password);
    setUser(userData);
    setLoading(false);
  };

  const logout = () => {
    setUser(null);
  };

  return (
    <AuthContext.Provider value={{ user, loading, login, logout }}>
      {props.children}
    </AuthContext.Provider>
  );
}

function useAuth() {
  return useContext(AuthContext);
}

Common Mistakes

  1. Creating context inside a component: Context should be created at module level, not inside a component function.
  2. Not providing a default value: The default value to createContext() is used when no provider exists. Always provide a sensible default.
  3. Overusing context: Not everything needs context. Use props for simple parent-child communication.
  4. Mutating context values: Context values should be signals or derived values. Direct mutations bypass reactivity.
  5. Putting too much in one context: Split unrelated concerns into separate contexts (theme, auth, settings).

Practice Questions

  1. What does createContext return? Answer: A context object with Provider component and optional default value.

  2. How do you access context in a child component? Answer: Call useContext(ContextObject) which returns the current context value from the nearest provider.

  3. What happens if you use context without a provider? Answer: It returns the default value passed to createContext(). If no default was given, it returns undefined.

  4. Why put signals in context instead of raw values? Answer: Signals maintain reactivity. Consumers that read the signal get updated values. Raw values are snapshots.

Challenge

Build a multi-provider system: ThemeProvider (light/dark mode), AuthProvider (user state), and SettingsProvider (language, notifications). Consume all three in a settings panel component.

Mini Project

Create a todo app with context for state management: a TodoProvider holds the todos signal and CRUD functions, the main page consumes context, and child components (TodoList, TodoInput, TodoFilters) access shared state through context.

FAQ

Can I have multiple context providers?

: Yes. Nest providers for different concerns. Each context is independent.

Does context cause unnecessary re-renders?

: In Solid.js, components that consume context only update when the specific signals they read change, not when any context value changes.

Can I update context from a child?

: Yes. Provide setter functions in the context value. Children can call these to update shared state.

Should I use context or props for shared state?

: Use props for direct parent-child relationships. Use context for global or deeply shared state.

What's Next

Learn about Solid.js Portals for rendering components outside the DOM hierarchy.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro