A lightweight, simple feature flag library for React applications with local override support.
- FlagProvider: React Context provider for default flag configuration
- useFlag Hook: Simple hook that returns boolean values
- Priority System: Local override → Provider value → false
- localStorage Persistence: Override flags persist across sessions
- TypeScript Support: Full TypeScript definitions included
- Tiny Bundle Size: Minimal footprint for your application
- SSR Safe: Works with server-side rendering
npm install @uikudo/useflag
# or
pnpm add @uikudo/useflag
# or
yarn add @uikudo/useflagimport { FlagProvider } from '@uikudo/useflag';
ReactDOM.createRoot(document.getElementById('root')!).render(
<FlagProvider flags={{ darkMode: true, premium: false }}>
<App />
</FlagProvider>
);import { useFlag } from '@uikudo/useflag';
function MyComponent() {
const isDarkMode = useFlag('darkMode');
const isPremium = useFlag('premium');
return (
<div className={isDarkMode ? 'dark' : 'light'}>
{isPremium && <PremiumFeature />}
</div>
);
}import { setFlagOverride, clearFlagOverride } from '@uikudo/useflag';
// Set an override
setFlagOverride('darkMode', false);
// Clear an override (falls back to provider value)
clearFlagOverride('darkMode');Provides default flag configuration to your application.
Props:
flags?: FlagConfig- Object mapping flag names to boolean valueschildren: ReactNode- Your application components
Example:
<FlagProvider flags={{
darkMode: true,
newFeature: false,
beta: true
}}>
<App />
</FlagProvider>Hook to access a feature flag value.
Parameters:
name: string- The name of the flag
Returns:
boolean- The current flag value
Priority:
- Local override (from localStorage)
- Provider value (from FlagProvider)
false(default)
Example:
const isDarkMode = useFlag('darkMode');
const isNewFeature = useFlag('newFeature');Set a local override for a flag. Stored in localStorage and persists across sessions.
Parameters:
name: string- Flag namevalue: boolean- Flag value
Example:
setFlagOverride('darkMode', true);Clear a local override. Flag will fall back to provider value or false.
Parameters:
name: string- Flag name
Example:
clearFlagOverride('darkMode');Clear all local overrides.
Example:
clearAllFlagOverrides();Get all current local overrides.
Returns:
FlagConfig- Object with all override flags
Example:
const overrides = getAllFlagOverrides();
console.log(overrides); // { darkMode: true, premium: false }Flags are resolved with the following priority:
-
Local Override (highest priority)
- Stored in
localStoragewith keyuseflag:overrides - Persists across browser sessions
- Set via
setFlagOverride()
- Stored in
-
Provider Value
- Defined in
<FlagProvider flags={...}> - Application-level defaults
- Defined in
-
Default Value (lowest priority)
- Always
falseif not defined elsewhere
- Always
Overrides are stored in localStorage under the key useflag:overrides:
{
"darkMode": true,
"premium": false,
"beta": true
}Full TypeScript support included:
import type { FlagConfig } from '@uikudo/useflag';
const myFlags: FlagConfig = {
darkMode: true,
premium: false,
};import { FlagProvider, useFlag } from '@uikudo/useflag';
function App() {
return (
<FlagProvider flags={{ darkMode: true }}>
<Dashboard />
</FlagProvider>
);
}
function Dashboard() {
const isDarkMode = useFlag('darkMode');
return (
<div className={isDarkMode ? 'dark-theme' : 'light-theme'}>
Dashboard
</div>
);
}import { useFlag, setFlagOverride } from '@uikudo/useflag';
function FeatureToggle() {
const isEnabled = useFlag('newFeature');
return (
<div>
<p>Feature is {isEnabled ? 'enabled' : 'disabled'}</p>
<button onClick={() => setFlagOverride('newFeature', !isEnabled)}>
Toggle Feature
</button>
</div>
);
}import { getAllFlagOverrides, clearAllFlagOverrides } from '@uikudo/useflag';
function DevTools() {
const [overrides, setOverrides] = useState(getAllFlagOverrides());
const handleReset = () => {
clearAllFlagOverrides();
setOverrides({});
};
return (
<div>
<h3>Current Overrides</h3>
<pre>{JSON.stringify(overrides, null, 2)}</pre>
<button onClick={handleReset}>Reset All</button>
</div>
);
}- Define flags in one place: Use
FlagProviderat your app root with all flags - Use descriptive names:
darkMode,premiumFeatures,experimentalUI - Document your flags: Keep a list of all flags and their purposes
- Clean up old flags: Remove unused flags from your codebase
- Dev tools: Create a dev panel to toggle flags during development
Works in all modern browsers that support:
- React 18+
- localStorage
- CustomEvent API
MIT
Contributions welcome! Please open an issue or PR.
uikudo