Skip to main content
All articles
Tutorial July 1, 2026 8 min read

How to Build a Settings Page in React with Tabs

A complete guide to building a tabbed settings page in React: profile, notifications, billing, and API keys — all accessible, all with Ninna UI components.

By Ninna UI Team


Settings pages are a staple of SaaS apps — and they're a great showcase for tab navigation, form components, and accessible interaction patterns. Let's build one with Ninna UI.

1. Tab structure

Use the Tabs component from @ninna-ui/navigation. It handles arrow-key navigation, ARIA tablist semantics, and focus management:

import { Tabs } from "@ninna-ui/navigation";
import { Container } from "@ninna-ui/layout";
export function SettingsPage() {
return (
<Container className="py-8 max-w-3xl">
<Tabs defaultValue="profile">
<Tabs.List>
<Tabs.Trigger value="profile">Profile</Tabs.Trigger>
<Tabs.Trigger value="notifications">Notifications</Tabs.Trigger>
<Tabs.Trigger value="billing">Billing</Tabs.Trigger>
<Tabs.Trigger value="api-keys">API Keys</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="profile">{/* Profile form */}</Tabs.Content>
<Tabs.Content value="notifications">{/* Notification toggles */}</Tabs.Content>
<Tabs.Content value="billing">{/* Billing info */}</Tabs.Content>
<Tabs.Content value="api-keys">{/* API key management */}</Tabs.Content>
</Tabs>
</Container>
);
}

2. Profile tab

import { Field, Input, Textarea } from "@ninna-ui/forms";
import { Button, Avatar } from "@ninna-ui/primitives";
import { VStack } from "@ninna-ui/layout";
<VStack gap="4">
<Avatar name="Jane Doe" size="xl" />
<Field label="Display name" htmlFor="name">
<Input id="name" defaultValue="Jane Doe" />
</Field>
<Field label="Bio" htmlFor="bio">
<Textarea id="bio" rows={3} defaultValue="Product designer" />
</Field>
<Button color="primary">Save changes</Button>
</VStack>

3. Notifications tab

Use Switch components for toggle settings. Remember: Switch uses onCheckedChange, not onChange:

import { Switch } from "@ninna-ui/forms";
import { VStack } from "@ninna-ui/layout";
import { Text } from "@ninna-ui/primitives";
<VStack gap="4">
<div className="flex items-center justify-between">
<Text>Email notifications</Text>
<Switch defaultChecked />
</div>
<div className="flex items-center justify-between">
<Text>Push notifications</Text>
<Switch />
</div>
<div className="flex items-center justify-between">
<Text>Weekly digest</Text>
<Switch defaultChecked />
</div>
</VStack>

4. API keys tab

import { Button, Badge, Code } from "@ninna-ui/primitives";
import { VStack, HStack } from "@ninna-ui/layout";
<VStack gap="3">
<HStack justify="between">
<Code>sk_live_****...****</Code>
<Button size="sm" variant="outline">Rotate</Button>
</HStack>
<HStack justify="between">
<Code>sk_test_****...****</Code>
<Button size="sm" variant="outline">Rotate</Button>
</HStack>
<Button color="primary" size="sm">Create new key</Button>
</VStack>

There's a ready-made Settings block at /blocks/api-keys-settings that includes this pattern with copy-to-clipboard and delete confirmation.


Build it with Ninna UI

Accessible React components, CSS-only theming, Tailwind v4 native.

Get Started

Keep reading