Skip to main content

Components

The React Native SDK provides declarative components for conditional rendering based on feature flags.

Each committed component evaluation records the effective checked leaves when frontend telemetry is enabled. Internal snapshot projection is silent, and rendering never implies a usage or view event. Record those events explicitly through useToggly.

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​

PropTypeDefaultDescription
featureKeystring-Single feature key to check
featureKeysstring[]-Multiple feature keys to check
requirement'all' | 'any''all'Whether all or any features must be enabled
negatebooleanfalseRender children when the feature is off
loadingReactNode-Content to show while loading
childrenReactNode-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​

  1. Use meaningful feature keys - Names like new-checkout are better than feature-123
  2. Pair on and off with negate - Use a second <Feature negate> for the alternate UI
  3. Keep feature trees shallow - Don't nest too many Feature components
  4. Consider loading states - Show appropriate loading UI while flags are being fetched
  5. Clean up old features - Remove Feature components once features are fully rolled out