React

Use Flipswitch feature flags in React with hooks and real-time updates

The OpenFeature React SDK provides React-specific hooks and components on top of the Flipswitch web provider. Flags evaluate client-side and re-render automatically when values change via SSE.

See the JavaScript SDK for full provider configuration (polling fallback, offline support, etc.).

Installation

npm install @flipswitch-io/web-provider @openfeature/react-sdk
yarn add @flipswitch-io/web-provider @openfeature/react-sdk
pnpm add @flipswitch-io/web-provider @openfeature/react-sdk

@openfeature/react-sdk re-exports everything from @openfeature/web-sdk, so you do not need to install it separately.

Quick Start

import { OpenFeatureProvider, OpenFeature, useFlag } from '@openfeature/react-sdk';
import { FlipswitchWebProvider } from '@flipswitch-io/web-provider';

// Initialize once at app startup
OpenFeature.setProvider(
  new FlipswitchWebProvider({ apiKey: 'YOUR_API_KEY' })
);

function App() {
  return (
    <OpenFeatureProvider>
      <MyComponent />
    </OpenFeatureProvider>
  );
}

function MyComponent() {
  const { value: darkMode } = useFlag('dark-mode', false);

  return (
    <div className={darkMode ? 'dark' : 'light'}>
      Dark mode is {darkMode ? 'enabled' : 'disabled'}
    </div>
  );
}

useFlag Hook

useFlag infers the flag type from the default value and returns a query object:

const { value, reason, variant, isError, errorMessage } = useFlag('flag-key', defaultValue);

Works with all flag types:

const { value: enabled } = useFlag('new-feature', false);           // boolean
const { value: greeting } = useFlag('welcome-message', 'Hello!');   // string
const { value: limit } = useFlag('max-items', 10);                  // number
const { value: config } = useFlag('ui-config', { theme: 'light' }); // object

Typed Hooks

If you prefer explicit typing, use the type-specific hooks:

import {
  useBooleanFlagValue,
  useBooleanFlagDetails,
  useStringFlagValue,
  useNumberFlagValue,
  useObjectFlagValue,
} from '@openfeature/react-sdk';

const darkMode = useBooleanFlagValue('dark-mode', false);
const details = useBooleanFlagDetails('dark-mode', false);
// details.value, details.variant, details.reason

Real-Time Updates

The useFlag hook automatically re-renders when flag values change via SSE. No additional setup is needed beyond enabling real-time updates on the provider (enabled by default).

function Banner() {
  // This component re-renders whenever 'promo-banner' changes in Flipswitch
  const { value: showBanner } = useFlag('promo-banner', false);

  if (!showBanner) return null;
  return <div className="banner">Special offer!</div>;
}

Re-renders are triggered by the Flipswitch provider emitting PROVIDER_CONFIGURATION_CHANGED events when it receives SSE updates.

Evaluation Context

Set user context for targeting rules. Context can be set globally or updated from within components:

Global Context

import { OpenFeature } from '@openfeature/react-sdk';

// Set context before or after provider initialization
OpenFeature.setContext({
  targetingKey: 'user-123',
  email: 'user@example.com',
  plan: 'premium',
});

Context Mutator Hook

Update context from within components using useContextMutator:

import { useContextMutator } from '@openfeature/react-sdk';

function UserProfile({ user }) {
  const { setContext } = useContextMutator();

  useEffect(() => {
    setContext({
      targetingKey: user.id,
      email: user.email,
      plan: user.plan,
    });
  }, [user]);

  return <FeatureEnabledContent />;
}

Suspense Support

Suspend rendering until the provider is ready, avoiding flashes of default values:

import { useSuspenseFlag } from '@openfeature/react-sdk';
import { Suspense } from 'react';

function Feature() {
  const { value: enabled } = useSuspenseFlag('new-feature', false);
  return enabled ? <NewFeature /> : <OldFeature />;
}

function App() {
  return (
    <OpenFeatureProvider>
      <Suspense fallback={<Loading />}>
        <Feature />
      </Suspense>
    </OpenFeatureProvider>
  );
}

You can also enable suspense selectively on useFlag:

const { value } = useFlag('my-flag', false, { suspend: true });

FeatureFlag Component

For declarative conditional rendering without hooks:

import { FeatureFlag } from '@openfeature/react-sdk';

function Page() {
  return (
    <FeatureFlag flagKey="dark-mode" defaultValue={false} fallback={<LightTheme />}>
      <DarkTheme />
    </FeatureFlag>
  );
}

With a render function for access to the evaluated value:

<FeatureFlag flagKey="welcome-message" defaultValue="Hello!">
  {({ value }) => <h1>{value}</h1>}
</FeatureFlag>

Domain-Scoped Providers

Use separate providers for different parts of your app:

OpenFeature.setProvider('checkout', new FlipswitchWebProvider({ apiKey: 'CHECKOUT_KEY' }));

function CheckoutPage() {
  return (
    <OpenFeatureProvider domain="checkout">
      <CheckoutFeatures />
    </OpenFeatureProvider>
  );
}

Next.js

In Next.js App Router, the provider setup must happen in a Client Component:

'use client';

import { OpenFeatureProvider, OpenFeature } from '@openfeature/react-sdk';
import { FlipswitchWebProvider } from '@flipswitch-io/web-provider';

OpenFeature.setProvider(
  new FlipswitchWebProvider({ apiKey: 'YOUR_API_KEY' })
);

export function FeatureFlagProvider({ children }: { children: React.ReactNode }) {
  return <OpenFeatureProvider>{children}</OpenFeatureProvider>;
}

Then use in your layout:

import { FeatureFlagProvider } from './feature-flag-provider';

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <FeatureFlagProvider>{children}</FeatureFlagProvider>
      </body>
    </html>
  );
}

Testing

Use OpenFeatureTestProvider for deterministic flag values in tests:

import { OpenFeatureTestProvider } from '@openfeature/react-sdk';
import { render } from '@testing-library/react';

render(
  <OpenFeatureTestProvider flagValueMap={{ 'dark-mode': true, 'max-items': 25 }}>
    <MyComponent />
  </OpenFeatureTestProvider>
);

On this page