@omniretail/omniflags-react
v1.0.25
Published
OmniFlags React SDK — provider + hooks for feature flags
Downloads
2,757
Readme
@omniretail/omniflags-react
React SDK for OmniFlags.
Installation
npm install @omniretail/omniflags-reactQuick start
Wrap your app with OmniFlagsProvider and use the hooks anywhere below it.
import { OmniFlagsProvider, useFlag } from "@omniretail/omniflags-react";
function App() {
return (
<OmniFlagsProvider sdkKey="your-sdk-key">
<MyApp />
</OmniFlagsProvider>
);
}
function MyApp() {
const darkMode = useFlag("store.dark-mode");
return <div className={darkMode ? "dark" : "light"}>...</div>;
}Provider
<OmniFlagsProvider sdkKey="your-sdk-key">
{children}
</OmniFlagsProvider>| Prop | Type | Description |
|------|------|-------------|
| sdkKey | string | Required. SDK key from the OmniFlags dashboard. |
Hooks
useFlag
Evaluates a boolean flag.
const enabled = useFlag("store.show-banner");
const enabled = useFlag("store.show-banner", { customerId: "cust-123" }); // with context
const enabled = useFlag("store.show-banner", undefined, false); // custom defaultuseFlagValue
Returns the typed value of a flag.
const theme = useFlagValue<string>("store.theme", "light");
const limit = useFlagValue<number>("store.item-limit", 10);
const theme = useFlagValue<string>("store.theme", "light", { businessId: "biz-456" }); // with contextuseFlagVariant
Returns the full evaluation result — value, variant, reason, and which rule matched.
const result = useFlagVariant("store.show-banner");
// result.value, result.variant, result.reason, result.ruleId, result.errorCodeuseFlagStatus
Returns the current loading state of the flag client.
const { isFetching, isLoading, origin, error } = useFlagStatus();| Field | Type | Description |
|-------|------|-------------|
| isFetching | boolean | A network request is in flight. |
| isLoading | boolean | No flags have been loaded yet (first fetch pending). |
| origin | FlagOrigin | Where the current flags came from: "NONE", "CACHE", or "SERVER". |
| error | Error \| null | The last fetch error, or null. |
function FlagGate({ children }: { children: React.ReactNode }) {
const { isLoading } = useFlagStatus();
if (isLoading) return <Spinner />;
return <>{children}</>;
}useOmniFlags
Low-level access to the underlying client and ready state.
const { client, ready } = useOmniFlags();Context
Context is passed per evaluation call — customer, business, branch, country, etc. There is no persistent context state.
function Banner({ customerId, businessId }: Props) {
const ctx = { customerId, businessId };
const show = useFlag("store.show-banner", ctx);
return show ? <Banner /> : null;
}Flag keys
Keys are namespaced by project: {projectKey}.{flagKey}. Find the full flag key in the OmniFlags dashboard on the flag detail page.
Next.js (App Router)
Add the provider to your root layout. Store the SDK key in .env.local:
NEXT_PUBLIC_OMNIFLAGS_SDK_KEY=your-sdk-key// app/layout.tsx
import { OmniFlagsProvider } from '@omniretail/omniflags-react'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html>
<body>
<OmniFlagsProvider sdkKey={process.env.NEXT_PUBLIC_OMNIFLAGS_SDK_KEY!}>
{children}
</OmniFlagsProvider>
</body>
</html>
)
}Use hooks inside 'use client' components. Flag evaluation happens on the client after the first fetch, so guard against the initial loading state where needed:
'use client'
import { useFlagValue, useFlagStatus } from '@omniretail/omniflags-react'
export function CheckoutButton() {
const { isLoading } = useFlagStatus()
const useNewFlow = useFlagValue('checkout.new-flow', false)
if (isLoading) return null
return <button>{useNewFlow ? 'Express checkout' : 'Checkout'}</button>
}Server Components passed as children into the provider are unaffected — they still run on the server.
