@hauses/react-sdk
v0.1.3
Published
React SDK for Flags - Type-safe feature flags with hooks
Maintainers
Readme
@hauses/react-sdk
React SDK for feature flags with hooks and providers.
🌐 Website: flags.hauses.dev
Installation
npm install @hauses/react-sdk
# or
yarn add @hauses/react-sdk
# or
pnpm add @hauses/react-sdk
# or
bun add @hauses/react-sdkFeatures
- 🎣 React Hooks - Simple
useFlagshook for feature checks - 🎯 Type-safe - Full TypeScript support with auto-generated types
- ⚡ Lightweight - Minimal bundle size
- 🔄 Real-time - Instant flag updates without redeployment
- 👥 Context targeting - Target flags based on user/company
- 🚀 Easy setup - Wrap your app and start using flags
- ⚛️ React 19 ready - Compatible with latest React versions
Quick Start
1. Wrap your app with FlagsProvider
import React from 'react';
import { FlagsProvider } from '@hauses/react-sdk';
function App() {
return (
<FlagsProvider
publishableKey="your_publishable_key"
context={{
user: {
key: 'user-123',
email: '[email protected]',
name: 'John Doe'
},
company: {
key: 'company-456',
name: 'Acme Inc'
}
}}
>
<YourApp />
</FlagsProvider>
);
}2. Use flags in your components
import { useFlags } from '@hauses/react-sdk';
function FeatureComponent() {
const { isEnabled, isLoading } = useFlags('new-feature');
if (isLoading) {
return <div>Loading...</div>;
}
return (
<div>
{isEnabled ? (
<NewFeature />
) : (
<OldFeature />
)}
</div>
);
}API Reference
<FlagsProvider>
Provider component that makes flags available throughout your component tree.
Props
interface FlagsProviderProps {
publishableKey: string;
context?: FlagsContext;
options?: HttpClientOptions;
children: React.ReactNode;
}publishableKey(string, required) - Your publishable key from flags.hauses.devcontext(object, optional) - User and company context for targetingoptions(object, optional) - HTTP client configuration optionschildren(ReactNode, required) - Your React components
Example
<FlagsProvider
publishableKey={process.env.REACT_APP_FLAGS_KEY}
context={{
user: {
key: userId,
email: userEmail,
name: userName
},
company: {
key: companyId,
name: companyName
}
}}
options={{
baseUrl: 'https://flags.hauses.dev/api',
credentials: 'include'
}}
>
<App />
</FlagsProvider>useFlags(key)
Hook to check if a feature flag is enabled.
Parameters
key(string) - The flag key to check
Returns
{
isEnabled: boolean;
isLoading: boolean;
}isEnabled- Whether the flag is enabled (falseif loading or doesn't exist)isLoading- Whether flags are still being fetched
Example
function MyComponent() {
const darkMode = useFlags('dark-mode');
const betaFeature = useFlags('beta-feature');
if (darkMode.isLoading || betaFeature.isLoading) {
return <Skeleton />;
}
return (
<div className={darkMode.isEnabled ? 'dark' : 'light'}>
{betaFeature.isEnabled && <BetaFeature />}
<MainContent />
</div>
);
}TypeScript Support
Auto-generated Types
Use the @hauses/flags-cli to generate type definitions:
npm install -D @hauses/flags-cliAdd to your package.json:
{
"scripts": {
"flags:pull": "flags-cli pull --env REACT_APP_FLAGS_KEY --out src/flags.d.ts"
}
}Run the command:
npm run flags:pullThis generates a flags.d.ts file:
import "@hauses/react-sdk";
declare module "@hauses/react-sdk" {
export interface FlagValues {
"dark-mode": boolean;
"beta-feature": boolean;
"new-dashboard": boolean;
}
}Now you get autocomplete and type safety:
// ✅ TypeScript knows these flags exist
useFlags('dark-mode');
useFlags('beta-feature');
// ❌ TypeScript error - unknown flag
useFlags('unknown-flag');Context & Targeting
Context Types
interface FlagsContext {
user?: {
key: string; // required - unique user identifier
name?: string; // optional - user's display name
email?: string; // optional - user's email address
};
company?: {
key: string; // required - unique company identifier
name?: string; // optional - company's display name
};
}Dynamic Context Updates
The context automatically updates when the prop changes:
function App() {
const [user, setUser] = useState(null);
return (
<FlagsProvider
publishableKey={key}
context={{
user: user ? {
key: user.id,
email: user.email,
name: user.name
} : undefined
}}
>
<YourApp />
</FlagsProvider>
);
}Advanced Usage
Conditional Rendering
function Dashboard() {
const newDashboard = useFlags('new-dashboard');
return newDashboard.isEnabled ? <NewDashboard /> : <LegacyDashboard />;
}Multiple Flags
function Features() {
const feature1 = useFlags('feature-1');
const feature2 = useFlags('feature-2');
const feature3 = useFlags('feature-3');
return (
<div>
{feature1.isEnabled && <Feature1 />}
{feature2.isEnabled && <Feature2 />}
{feature3.isEnabled && <Feature3 />}
</div>
);
}Loading States
function MyComponent() {
const flag = useFlags('my-feature');
if (flag.isLoading) {
return <Spinner />;
}
return flag.isEnabled ? <NewUI /> : <OldUI />;
}Environment Variables
Create React App
<FlagsProvider publishableKey={process.env.REACT_APP_FLAGS_KEY}>Vite
<FlagsProvider publishableKey={import.meta.env.VITE_FLAGS_KEY}>Next.js
<FlagsProvider publishableKey={process.env.NEXT_PUBLIC_FLAGS_KEY}>Server-Side Rendering (SSR)
The SDK is SSR-compatible. On the server, flags will be in loading state initially:
function MyComponent() {
const flag = useFlags('feature');
// On server: isLoading = true, isEnabled = false
// On client (after hydration): Real values loaded
if (flag.isLoading) {
return <div>Loading...</div>;
}
return flag.isEnabled ? <Feature /> : null;
}Examples
A/B Testing
function PricingPage() {
const newPricing = useFlags('new-pricing-ui');
return newPricing.isEnabled ? (
<PricingV2 />
) : (
<PricingV1 />
);
}Feature Rollout
function Editor() {
const richEditor = useFlags('rich-text-editor');
return richEditor.isEnabled ? (
<RichTextEditor />
) : (
<SimpleTextarea />
);
}Beta Features
function Navigation() {
const betaMode = useFlags('beta-mode');
return (
<nav>
<HomeLink />
<ProfileLink />
{betaMode.isEnabled && <BetaFeaturesLink />}
</nav>
);
}Best Practices
1. Wrap at the root level
// ✅ Good - Wrap at root
function App() {
return (
<FlagsProvider publishableKey={key}>
<Router>
<Routes />
</Router>
</FlagsProvider>
);
}
// ❌ Bad - Multiple providers
function App() {
return (
<Router>
<FlagsProvider publishableKey={key}>
<Route1 />
</FlagsProvider>
<FlagsProvider publishableKey={key}>
<Route2 />
</FlagsProvider>
</Router>
);
}2. Handle loading states
// ✅ Good - Handle loading
function Feature() {
const flag = useFlags('feature');
if (flag.isLoading) return <Skeleton />;
return flag.isEnabled ? <New /> : <Old />;
}
// ❌ Bad - Ignore loading
function Feature() {
const flag = useFlags('feature');
return flag.isEnabled ? <New /> : <Old />; // Flickers during load
}3. Use TypeScript types
// ✅ Good - Type-safe
useFlags('known-flag'); // TypeScript validates this
// ❌ Bad - No validation
useFlags('typo-in-flg-name'); // Runtime errorPeer Dependencies
- React ^19.0.0
- React-DOM ^19.0.0
Also works with React 18.x.
Browser Support
Works in all modern browsers that support:
- ES6+ / ES2015+
- React 18+
- Fetch API
License
MIT
Support
- 📧 Email: [email protected]
- 🌐 Website: flags.hauses.dev
- 📖 Documentation: flags.hauses.dev/docs
- 🐛 Issues: GitHub Issues
Part of the Flags SDK monorepo.
