Components
The React Native SDK provides declarative components for conditional rendering based on feature flags.
Feature Component
Conditionally renders content when a feature is on. Set negate to render when it is off — the same pattern as Next.js and .NET.
Basic Usage
import { Feature } from '@ops-ai/react-native-toggly';
// Show when enabled
<Feature featureKey="new-feature">
<NewFeatureContent />
</Feature>
// Show when disabled
<Feature featureKey="new-feature" negate>
<LegacyFeatureContent />
</Feature>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
featureKey | string | - | Single feature key to check |
featureKeys | string[] | - | Multiple feature keys to check |
requirement | 'all' | 'any' | 'all' | Whether all or any features must be enabled |
negate | boolean | false | Render children when the feature is off |
loading | ReactNode | - | Content to show while loading |
children | ReactNode | - | Content when the gate passes |
Examples
Multiple Features (All Required)
<Feature featureKeys={['feature1', 'feature2']}>
<Text>Shown when BOTH features are enabled</Text>
</Feature>
Multiple Features (Any Required)
<Feature featureKeys={['feature1', 'feature2']} requirement="any">
<Text>Shown when AT LEAST ONE feature is enabled</Text>
</Feature>
On and Off Paths
<Feature featureKey="premium-feature">
<PremiumContent />
</Feature>
<Feature featureKey="premium-feature" negate>
<UpgradePrompt />
</Feature>
With Loading State
<Feature
featureKey="new-feature"
loading={<SkeletonLoader />}
>
<NewFeatureContent />
</Feature>
Complex Example
<Feature
featureKeys={['premium-subscription', 'advanced-analytics']}
requirement="all"
loading={<ActivityIndicator size="large" />}
>
<AdvancedAnalyticsDashboard />
</Feature>
<Feature
featureKeys={['premium-subscription', 'advanced-analytics']}
requirement="all"
negate
loading={<ActivityIndicator size="large" />}
>
<View style={styles.upgradeCard}>
<Text>Upgrade to Premium for advanced analytics</Text>
<Button title="Upgrade Now" onPress={handleUpgrade} />
</View>
</Feature>
Comparison: Component vs Hook
Choose the right approach for your use case:
Use Feature Component When:
- You want declarative, readable JSX
- The feature controls visibility of entire component trees
- You need built-in loading handling
<Feature featureKey="new-dashboard">
<NewDashboard />
</Feature>
<Feature featureKey="new-dashboard" negate>
<OldDashboard />
</Feature>
Use useFeatureFlag Hook When:
- You need the flag value for logic beyond rendering
- You want more control over the component behavior
- You're using the flag in event handlers or effects
function DashboardScreen() {
const { isEnabled } = useFeatureFlag('new-dashboard');
useEffect(() => {
if (isEnabled) {
analytics.track('new_dashboard_viewed');
}
}, [isEnabled]);
return isEnabled ? <NewDashboard /> : <OldDashboard />;
}
Patterns
Feature-Gated Navigation
function BottomNavigation() {
return (
<TabNavigator>
<Tab name="Home" component={HomeScreen} />
<Tab name="Search" component={SearchScreen} />
<Feature featureKey="social-features">
<Tab name="Friends" component={FriendsScreen} />
</Feature>
<Tab name="Profile" component={ProfileScreen} />
</TabNavigator>
);
}
Feature-Gated Form Fields
function SettingsForm() {
return (
<Form>
<TextField name="name" label="Name" />
<TextField name="email" label="Email" />
<Feature featureKey="advanced-settings">
<TextField name="apiKey" label="API Key" />
<Switch name="darkMode" label="Dark Mode" />
</Feature>
<Button type="submit">Save</Button>
</Form>
);
}
A/B Testing UI Variants
function HeroSection() {
return (
<View>
<Feature featureKey="hero-variant-a">
<HeroVariantA />
</Feature>
<Feature featureKey="hero-variant-b">
<HeroVariantB />
</Feature>
{/* Default when neither variant is enabled */}
<Feature
featureKeys={['hero-variant-a', 'hero-variant-b']}
requirement="any"
negate
>
<DefaultHero />
</Feature>
</View>
);
}
Gradual Rollout
function CheckoutFlow() {
return (
<>
<Feature
featureKey="new-checkout-flow"
loading={<CheckoutSkeleton />}
>
<NewCheckout />
</Feature>
<Feature
featureKey="new-checkout-flow"
negate
loading={<CheckoutSkeleton />}
>
<LegacyCheckout />
</Feature>
</>
);
}
Entity context
<Feature featureKey="OrderBadge" context={order} contextKind="Order">
<Badge />
</Feature>
Entity is per widget. setIdentity is user. Clients do not register schemas. See Entity & page context.
Best Practices
- Use meaningful feature keys - Names like
new-checkoutare better thanfeature-123 - Pair on and off with
negate- Use a second<Feature negate>for the alternate UI - Keep feature trees shallow - Don't nest too many Feature components
- Consider loading states - Show appropriate loading UI while flags are being fetched
- Clean up old features - Remove Feature components once features are fully rolled out