The Flagdeck React SDK provides an easy way to use feature flags in React applications. Built on top of the JavaScript SDK, it offers React-specific components and hooks for a more idiomatic integration with your React projects.
Install the React SDK using npm, yarn, or pnpm:
# Using npm
npm install @flagdeck/react
# Using yarn
yarn add @flagdeck/react
# Using pnpm
pnpm add @flagdeck/react
The SDK automatically installs the Flagdeck JavaScript SDK as a dependency.
Wrap your application with the FlagdeckProvider
and start using the hooks and components:
import React from 'react';
import { FlagdeckProvider, useFlag } from '@flagdeck/react';
function App() {
return (
<FlagdeckProvider
options={{
apiKey: 'YOUR_API_KEY',
realTimeUpdates: true,
}}
>
<YourApp />
</FlagdeckProvider>
);
}
function YourApp() {
const { isEnabled, isLoading } = useFlag('new-feature');
if (isLoading) return <div>Loading...</div>;
return (
<div>
{isEnabled ? 'New feature is enabled!' : 'New feature is disabled'}
</div>
);
}
The FlagdeckProvider
initializes the Flagdeck SDK and provides the client instance to all child components.
<FlagdeckProvider
options={{
apiKey: 'your-api-key', // Required
debug: true, // Optional: enables debug logging
realTimeUpdates: true, // Optional: enables real-time flag updates via SSE
timeout: 5000, // Optional: API request timeout in ms
enableCache: true, // Optional: enables caching of flag evaluations
cacheTimeout: 30000, // Optional: cache TTL in ms
enableOfflineMode: false, // Optional: enables offline fallback
enableAnalytics: true, // Optional: enables analytics tracking
}}
initialContext={{ // Optional: initial user context
userId: 'user-123', // User identifier
attributes: { // User attributes for targeting
country: 'US',
plan: 'premium'
}
}}
readyDelayMs={100} // Optional: delay before marking SDK as ready
>
{children}
</FlagdeckProvider>
Access the Flagdeck client and context:
import { useFlagdeck } from '@flagdeck/react';
function UserSettings() {
const {
client, // Flagdeck client instance
isReady, // True when SDK is initialized and ready
error, // Error object if SDK initialization failed
context, // Current user context
setContext // Function to update user context
} = useFlagdeck();
// Update user context based on selections
const handlePlanChange = (plan) => {
setContext({
...context,
attributes: {
...context?.attributes,
plan
}
});
};
return (
<div>
{!isReady && <div>Loading SDK...</div>}
{error && <div>Error: {error.message}</div>}
{isReady && (
<select
value={context?.attributes?.plan || 'free'}
onChange={(e) => handlePlanChange(e.target.value)}
>
<option value="free">Free Plan</option>
<option value="premium">Premium Plan</option>
</select>
)}
</div>
);
}
Evaluate a boolean feature flag:
import { useFlag } from '@flagdeck/react';
function FeatureComponent() {
const {
isEnabled, // Boolean flag value
isLoading, // True when flag is being evaluated
error // Error object if evaluation failed
} = useFlag('new-dashboard', false); // 'false' is the default value
if (isLoading) return <div>Loading...</div>;
if (error) {
console.warn(`Flag error: ${error.message}`);
// Continue with default value
}
return (
<div>
{isEnabled ? <NewDashboard /> : <LegacyDashboard />}
</div>
);
}
Get a feature flag value of any type:
import { useFlagValue } from '@flagdeck/react';
function ThemeComponent() {
const {
value: theme, // Flag value (can be any type)
isLoading, // True when flag is being evaluated
error // Error object if evaluation failed
} = useFlagValue('theme-variant', 'default'); // 'default' is the default value
// Apply different styles based on theme value
const themeStyles = {
default: { background: 'white', color: 'black' },
dark: { background: 'black', color: 'white' },
blue: { background: '#0070F3', color: 'white' }
};
const style = themeStyles[theme] || themeStyles.default;
return (
<div style={style}>
Current theme: {isLoading ? 'Loading...' : theme}
</div>
);
}
Evaluate multiple flags at once:
import { useFlags } from '@flagdeck/react';
function FeatureDashboard() {
const {
values, // Record of flag keys to their values
isLoading, // True when flags are being evaluated
errors // Record of flag keys to error objects
} = useFlags(['new-header', 'sidebar', 'analytics'], false);
if (isLoading) return <div>Loading features...</div>;
// Count enabled features
const enabledCount = Object.values(values).filter(Boolean).length;
return (
<div>
<p>Enabled features: {enabledCount}/{Object.keys(values).length}</p>
{values['new-header'] && <NewHeader />}
{values['sidebar'] && <Sidebar />}
{values['analytics'] && <AnalyticsPanel />}
{/* Example of handling errors */}
{Object.entries(errors).map(([key, error]) => (
<div key={key} className="error">
Error with {key}: {error.message}
</div>
))}
</div>
);
}
Conditionally render content based on flag state:
import { FeatureFlag } from '@flagdeck/react';
function Dashboard() {
return (
<div>
<h1>Dashboard</h1>
<FeatureFlag
flagKey="new-dashboard"
defaultEnabled={false}
fallback={<LegacyDashboard />}
loadingContent={<div>Loading dashboard...</div>}
onError={(error) => console.error('Dashboard flag error:', error)}
>
<NewDashboard />
</FeatureFlag>
</div>
);
}
Render prop component for accessing flag values:
import { FlagValue } from '@flagdeck/react';
function ThemeWrapper({ children }) {
return (
<FlagValue flagKey="color-theme" defaultValue="default">
{({ value: theme, isLoading }) => {
// Apply theme classes or styles based on the theme value
const themeClass = `theme-${isLoading ? 'default' : theme}`;
return (
<div className={themeClass}>
{isLoading && <div className="theme-loading-indicator" />}
{children}
</div>
);
}}
</FlagValue>
);
}
Render prop alternative for conditional rendering:
import { WithFeature } from '@flagdeck/react';
function PaymentOptions() {
return (
<div>
<h2>Payment Options</h2>
{/* Always shown payment methods */}
<CreditCardOption />
<PayPalOption />
{/* Conditionally shown new payment methods */}
<WithFeature flagKey="crypto-payments">
{({ isEnabled, isLoading }) => (
<>
{isLoading && <div>Loading payment options...</div>}
{isEnabled && <CryptoPaymentOption />}
</>
)}
</WithFeature>
</div>
);
}
The React SDK supports real-time updates via Server-Sent Events (SSE). When enabled, flag changes made in the Flagdeck dashboard will be pushed to your application immediately without requiring page refreshes.
<FlagdeckProvider
options={{
apiKey: 'your-api-key',
realTimeUpdates: true // Enable real-time updates
}}
>
<App />
</FlagdeckProvider>
Then in your components, the hooks will automatically update with new values when flags change:
function FeatureMonitor() {
const { isEnabled } = useFlag('monitored-feature');
// This will automatically re-render when the flag changes
return (
<div>
Feature status: {isEnabled ? 'Enabled' : 'Disabled'}
</div>
);
}
Set or update user context to target features to specific users:
function UserProfile() {
const { context, setContext } = useFlagdeck();
const handlePlanChange = (plan) => {
setContext({
...context,
attributes: {
...context?.attributes,
plan
}
});
};
return (
<div>
<h2>User Profile</h2>
<select
value={context?.attributes?.plan || 'free'}
onChange={(e) => handlePlanChange(e.target.value)}
>
<option value="free">Free Plan</option>
<option value="pro">Pro Plan</option>
<option value="enterprise">Enterprise Plan</option>
</select>
{/* This component will re-evaluate flags when user context changes */}
<FeaturePanel />
</div>
);
}
All hooks provide error information that you can use to handle different error scenarios:
function FeatureSection() {
const { isEnabled, error } = useFlag('beta-feature');
// Handle different error types
if (error) {
switch (error.type) {
case 'notfound':
return <div>This feature is not configured yet.</div>;
case 'inactive':
return <div>This feature is currently disabled.</div>;
case 'configuration':
return <div>There's a configuration issue with this feature.</div>;
default:
return <div>Error loading feature: {error.message}</div>;
}
}
// Normal rendering when no errors
return (
<div>
{isEnabled ? (
<div>Beta feature is enabled!</div>
) : (
<div>Beta feature is disabled.</div>
)}
</div>
);
}
import { useFlag } from '@flagdeck/react';
import { Navigate, Route } from 'react-router-dom';
function ProtectedFeatureRoute({
flagKey,
fallbackPath = '/access-denied',
children
}) {
const { isEnabled, isLoading } = useFlag(flagKey);
if (isLoading) {
return <div>Loading access...</div>;
}
return isEnabled ? children : <Navigate to={fallbackPath} />;
}
// Usage in routes
function AppRoutes() {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route
path="/beta-feature"
element={
<ProtectedFeatureRoute flagKey="beta-access">
<BetaFeature />
</ProtectedFeatureRoute>
}
/>
</Routes>
);
}
import React, { lazy, Suspense } from 'react';
import { useFlag } from '@flagdeck/react';
// Define components
const LegacyComponent = lazy(() => import('./LegacyComponent'));
const NewComponent = lazy(() => import('./NewComponent'));
function FeatureWithLazyLoad() {
const { isEnabled, isLoading } = useFlag('new-component');
if (isLoading) {
return <div>Loading feature flags...</div>;
}
// Choose which component to render based on flag
const Component = isEnabled ? NewComponent : LegacyComponent;
return (
<Suspense fallback={<div>Loading component...</div>}>
<Component />
</Suspense>
);
}
import { createContext, useContext } from 'react';
import { useFlagValue } from '@flagdeck/react';
// Create theme context
const ThemeContext = createContext({
theme: 'default',
isDark: false
});
function ThemeProvider({ children }) {
const { value: theme } = useFlagValue('app-boot-theme', 'default');
// Calculate theme properties
const themeData = {
theme,
isDark: theme === 'dark' || theme === 'midnight',
// Other theme properties...
};
useEffect(() => {
// Apply theme to document root
document.documentElement.setAttribute('data-theme', theme);
if (themeData.isDark) {
document.documentElement.classList.add('dark-mode');
} else {
document.documentElement.classList.remove('dark-mode');
}
}, [theme, themeData.isDark]);
return (
<ThemeContext.Provider value={themeData}>
{children}
</ThemeContext.Provider>
);
}
// Hook to use theme
const useTheme = () => useContext(ThemeContext);
The React SDK is built with TypeScript and provides full type definitions:
import { useFlag, useFlagValue } from '@flagdeck/react';
function TypedComponent() {
// Boolean flag
const { isEnabled } = useFlag('feature-flag');
// String flag with specific type
const { value: theme } = useFlagValue<'light' | 'dark' | 'system'>('theme', 'system');
// Number flag
const { value: limit } = useFlagValue<number>('rate-limit', 100);
// Complex object flag
interface ConfigType {
timeout: number;
retries: number;
endpoints: string[];
}
const defaultConfig: ConfigType = {
timeout: 3000,
retries: 3,
endpoints: ['api.example.com']
};
const { value: config } = useFlagValue<ConfigType>('api-config', defaultConfig);
return (
<div>
<p>Feature enabled: {String(isEnabled)}</p>
<p>Theme: {theme}</p>
<p>Rate limit: {limit}</p>
<p>API timeout: {config.timeout}ms</p>
</div>
);
}
Initialize Early: Place FlagdeckProvider
high in your component tree to make flags available throughout your app.
Handle Loading States: Always check isLoading
before using flag values to avoid flash of incorrect content.
Provide Default Values: Always specify default values that make sense for your application as fallbacks.
Use Error Boundaries: Wrap flag-dependent components in error boundaries to catch evaluation errors.
Batch Flag Evaluations: Use useFlags
to evaluate multiple flags at once for better performance.
Consider Server-Side Rendering: For SSR apps, provide sensible defaults and revalidate flags on the client side.
Keep User Context Updated: Always update user context when user attributes change to ensure correct targeting.
Cache Key Flags: Consider saving critical flags to local storage for offline use.
Minimize Re-renders: Use the useFlagdeck
hook only in components that need to access or update the user context.
Optimize Flag Access: Use useFlags
for multiple flags instead of multiple useFlag
calls.
Enable Caching: Keep the default caching enabled to reduce API calls.
Use Real-time Updates Wisely: Only enable real-time updates for flags that need immediate propagation.
For more detailed information about the underlying JavaScript SDK features and configuration options, refer to the JavaScript SDK documentation.
Start using Flagdeck today
Simple feature flag management for modern development teams.
Product
© 2025 Flagdeck. All rights reserved.