npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

superctx

v0.3.2

Published

An enhanced React Context API with better TypeScript support, error handling, and utilities for multiple contexts.

Downloads

763

Readme

SuperCtx

An ergonomic superset of React's Context API for butter smooth dependency injection 🧈

Warning

This library is meant to be used with the React Compiler. Relying heavily on the Context API without the React Compiler can cause serious performance sinks in your application.

Overview

superctx extends React's Context API with:

  • ✅ Better TypeScript inference than native Context API
  • ✅ Automatic error handling for missing providers
  • ✅ Enhanced base context providers with addBase
  • ✅ Easy access to multiple contexts
  • ✅ Lazy initialization of default values
  • ✅ Zero dependencies (only uses React)

Especially recommended for AI coding agents:

  • ✅ Less boilerplate means lower token consumption
  • ✅ More compact imports keep prompts and diffs shorter
  • ✅ Lower token usage leads to better iteration quality

Requirements

  • React 19 or above

Installation

pnpm add superctx

Usage

Basic Context Creation

import { createSuperContext } from "superctx";

// Context that requires a provider
const UserContext = createSuperContext<{ name: string; email: string }>({
  notProvidedMessage: "User context not provided",
});

// Context with default value
const ThemeContext = createSuperContext<"light" | "dark">({
  initialValue: "light",
});

// Context with lazy initialization
const ConfigContext = createSuperContext<AppConfig>({
  getInitialValue: () => loadConfigFromStorage(),
});

Using Contexts

function UserProfile() {
  const user = UserContext.useProvided();

  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.email}</p>
    </div>
  );
}

// Consumer pattern (alternative to hook)
function UserDisplay() {
  return <UserContext.Consumer>{(user) => <div>{user.name}</div>}</UserContext.Consumer>;
}

Base Components with addBase

Create root components that automatically provide context values:

import { createSuperContext, addBase } from "superctx";

const Environment = addBase(
  createSuperContext<NebulyEnvironment>({
    notProvidedMessage: "Environment not provided",
  }),
  (Provider) => {
    return ({ children }) => {
      const env = getEnvironmentValues();
      return <Provider value={env}>{children}</Provider>;
    };
  },
);

// Usage - just use the Base component
function App() {
  return (
    <Environment.Base>
      <YourApp />
    </Environment.Base>
  );
}

// Access the context anywhere
function Component() {
  const env = Environment.useProvided();
  return <div>{env.apiUrl}</div>;
}

Working with Multiple Contexts

Use useProviders to access multiple contexts at once:

import { useProviders } from "superctx";

function MyComponent() {
  const [user, theme, environment] = useProviders([UserContext, ThemeContext, Environment]);

  return (
    <div className={theme}>
      <h1>{user.name}</h1>
      <p>API: {environment.apiUrl}</p>
    </div>
  );
}

Consumer Component

Use the Consumer component for cleaner conditional rendering with multiple contexts:

import { Consumer } from "superctx";

function DataDisplay() {
  return (
    <Consumer providers={[UserContext, ProjectContext]}>
      {([user, project]) => (
        <div>
          <h1>{user.name}</h1>
          <h2>{project.name}</h2>
        </div>
      )}
    </Consumer>
  );
}

Real-World Examples

Environment Configuration

import { createSuperContext, addBase } from "superctx";

type NebulyEnvironment = {
  apiUrl: string;
  environment: "development" | "production";
  flags?: Record<string, boolean>;
};

export const Environment = addBase(
  createSuperContext<NebulyEnvironment>({
    notProvidedMessage: "Environment not provided",
  }),
  (Provider) => {
    return ({ children }) => {
      const env = getEnvironmentValues();
      return <Provider value={env}>{children}</Provider>;
    };
  },
);

// Usage
function App() {
  return (
    <Environment.Base>
      <Router />
    </Environment.Base>
  );
}

function ApiClient() {
  const { apiUrl } = Environment.useProvided();
  // Use apiUrl to configure API client
}

Theme Context

import { createSuperContext, addBase } from "superctx";

export const Theme = addBase(
  createSuperContext<"light" | "dark" | "system">({
    initialValue: "system",
  }),
  (Provider) => {
    return ({ children, defaultTheme = "system" }) => {
      const [theme, setTheme] = useState(defaultTheme);
      return <Provider value={theme}>{children}</Provider>;
    };
  },
);

// Usage
function App() {
  return (
    <Theme.Base defaultTheme="light">
      <YourApp />
    </Theme.Base>
  );
}

Combining Multiple Contexts

import { useProviders, Consumer } from "superctx";

// Access multiple contexts
function Dashboard() {
  const [user, project, environment] = useProviders([UserContext, ProjectContext, Environment]);

  return (
    <div>
      <h1>Welcome, {user.name}</h1>
      <p>Project: {project.name}</p>
      <p>Environment: {environment.environment}</p>
    </div>
  );
}

// Or use Consumer component for conditional rendering
function ConditionalContent() {
  return (
    <Consumer providers={[UserContext, FeatureFlags]}>
      {([user, flags]) => {
        if (flags.isAdmin && user.role === "admin") {
          return <AdminPanel />;
        }
        return <RegularContent />;
      }}
    </Consumer>
  );
}

Formatters with Locale

import { createSuperContext, addBase } from "superctx";
import { DateFormatter, NumberFormatter, TimeFormatter } from "formatters";

export const Formatters = addBase(
  createSuperContext<{
    numberFmt: NumberFormatter;
    timeFmt: TimeFormatter;
    dateFmt: DateFormatter;
  }>({
    notProvidedMessage: "Formatters are not provided",
  }),
  (Provider) => {
    return ({ children }) => {
      const { language } = Localization.useProvided();
      return (
        <Provider
          value={{
            numberFmt: new NumberFormatter({ locale: language }),
            timeFmt: new TimeFormatter({ locale: language }),
            dateFmt: new DateFormatter({ locale: language }),
          }}
        >
          {children}
        </Provider>
      );
    };
  },
);

// Usage
function PriceDisplay({ amount }: { amount: number }) {
  const { numberFmt } = Formatters.useProvided();
  return <span>{numberFmt.compactFloat(amount)}</span>;
}

API Reference

createSuperContext<T>(options)

Creates a super context with enhanced features.

Options:

  • initialValue: T: Default value (context is always provided)
  • getInitialValue: () => T: Lazy initialization function
  • notProvidedMessage: string: Error message if provider is missing

Returns:

  • Provider: React context provider component
  • Consumer: React context consumer component
  • useProvided(): Hook to access context value

addBase<T, U>(context, baseFactory)

Creates a base component for a context.

Parameters:

  • context: A super context
  • baseFactory: Function that takes Provider and returns a base component

Returns: Context with added Base component

useProviders<T>(deps)

Hook to access multiple contexts at once.

Parameters:

  • deps: Array of super contexts

Returns: Tuple of context values (typed)

Consumer<T>(props)

Component for conditional rendering with multiple contexts.

Props:

  • providers: Array of super contexts
  • children: Render function receiving context values

MissingProviderError

Error class thrown when a required context is not provided.

Error Handling

When a required context is missing, superctx throws a MissingProviderError as soon as you try to read it.

This fail-fast behavior is intentional: it surfaces provider mistakes immediately, instead of silently propagating null values and causing harder-to-debug errors later.

Vanilla

import { createContext, useContext } from "react";

export const MyContext = createContext<{
  foo: "bar";
}>(null!);

export function useMyContext() {
  const value = useContext(MyContext);
  if (!value) {
    throw new Error("useMyContext requires a MyContext provider");
  }
  return value;
}

export function SomeComponent() {
  const { foo } = useMyContext();
  return <p>{foo}</p>;
}

With superctx

import { createSuperContext } from "superctx";

export const MyContext = createSuperContext<{
  foo: "bar";
}>({
  notProvidedMessage: "MyContext provider is missing",
});

export function SomeComponent() {
  const { foo } = MyContext.useProvided();
  return <p>{foo}</p>;
}