Application content area
NavigationRail
A premium side navigation container designed for desktops. It balances high-level navigation with detailed content groups.
Preview
Usage
"use client";
import { Box, Flex, ListItem, Logo, NavGroup, NavItem, NavigationRail, Text } from '@photonix/ultimate';
import { DocumentOutline, HomeOutline, SettingsOutline } from '@photonix/icons';
export default function NavigationRailBasicExample() {
return (
<Flex h="100%" w="100%" align="stretch" border="1px solid var(--border-neutral-tertiary)" borderRadius="2xs" overflow="hidden">
<NavigationRail
mode="expanded"
header={<Logo height={48} format="full" />}
footer={
<ListItem
content="Alex Smith"
description="Pro Member"
leadingType="avatar"
avatarName="Alex Smith"
style={{ backgroundColor: 'var(--surface-neutral-on-surface)', borderRadius: 'var(--radius-sm)' }}
/>
}
>
<NavGroup label="Workspace" hideChevron>
<NavItem id="home" label="Home" icon={<HomeOutline />} selected />
<NavItem id="docs" label="Docs" icon={<DocumentOutline />} badge={8} />
<NavItem id="settings" label="Settings" icon={<SettingsOutline />} />
</NavGroup>
</NavigationRail>
<Box flex={1} p="md" bg="primary">
<Text color="secondary">Application content area</Text>
</Box>
</Flex>
);
}Component API
NavigationRail
Prop | Type | Default | Description |
|---|---|---|---|
mode | "expanded" | "collapsed" | 'expanded' | Sidebar mode |
header | React.ReactNode | - | Header content (logo, search, etc.) - fixed at top |
children | React.ReactNode | - | Navigation items - scrollable middle section |
footer | React.ReactNode | - | Footer content (CTA, ads, sticky items) - fixed at bottom |
expandedWidth | number | 280 | Width when expanded |
className | string | - | Additional class name |
height | string | number | '100%' | Height of the rail (default: 100%) |
floating | boolean | false | Whether to show a floating effect with shadow/border |
showFooterDivider | boolean | true | Whether to show a divider at the top of the footer (default: true) |
style | React.CSSProperties | - | Optional style object |
NavGroup
Prop | Type | Default | Description |
|---|---|---|---|
label | string | - | Group label |
expanded | boolean | true | Is group expanded |
hideChevron | boolean | false | Hide the expand/collapse chevron |
badge | boolean | - | Badge content (boolean for dot) |
children | React.ReactNode | - | Child items |
onToggle | (() => void) | - | On expand/collapse |
size | "sm" | "md" | 'md' | Size of the group header |
isFirstGroup | boolean | - | Internal: Is this the first group in the list |
NavItem
Prop | Type | Default | Description |
|---|---|---|---|
id | string | - | Unique identifier |
label | string | - | Item label |
icon | React.ReactNode | - | Leading icon (optional) |
badge | number | - | Badge content (number only) |
selected | boolean | false | Is this item selected |
disabled | boolean | false | Is this item disabled |
children | NavItemProps[] | - | Nested items (for tree structure) |
level | number | 0 | Indentation level |
size | "sm" | "md" | 'md' | Size of the item |
onClick | ((id: string) => void) | - | Click handler |
Variants
Collapsed Mode
Switch to collapsed mode for an icon-first rail.
Collapsed Mode
"use client";
import { AppsOutline, CalendarOutline, DocumentOutline } from '@photonix/icons';
import { Box, Flex, NavItem, NavigationRail } from '@photonix/ultimate';
export default function NavigationRailVariantCollapsedExample() {
return (
<Flex h={768} w="100%" align="stretch" border="1px solid var(--border-neutral-tertiary)" borderRadius="2xs" overflow="hidden">
<NavigationRail mode="collapsed">
<NavItem id="c1" label="Apps" icon={<AppsOutline />} selected />
<NavItem id="c2" label="Documents" icon={<DocumentOutline />} />
<NavItem id="c3" label="Calendar" icon={<CalendarOutline />} badge={5} />
</NavigationRail>
</Flex>
);
}With Groups
Organize items into manageable sections that can be expanded or collapsed.
With Groups
"use client";
import { AppsOutline, DocumentOutline, UserOutline } from '@photonix/icons';
import { Box, Flex, NavGroup, NavItem, NavigationRail } from '@photonix/ultimate';
import { useState } from 'react';
export default function NavigationRailVariantGroupsExample() {
const [expandedGroup, setExpandedGroup] = useState(true);
return (
<Flex h={768} w="100%" align="stretch" border="1px solid var(--border-neutral-tertiary)" borderRadius="2xs" overflow="hidden">
<NavigationRail>
<NavGroup label="Documents" expanded={expandedGroup} onToggle={() => setExpandedGroup((value) => !value)}>
<NavItem id="g1" label="Recent" icon={<DocumentOutline />} />
<NavItem id="g2" label="Shared with me" icon={<UserOutline />} />
<NavItem id="g3" label="Trash bin" icon={<DocumentOutline />} />
</NavGroup>
<NavGroup label="Support">
<NavItem id="g4" label="Help Center" icon={<AppsOutline />} />
</NavGroup>
</NavigationRail>
</Flex>
);
}Application Structure
A real-world example combining Logo, Search, upgrade prompts, and user profiles.
Application Structure
"use client";
import {
AppsOutline,
DocumentOutline,
SideBarCollapseOutline,
SideBarExpandOutline,
SparklesOutline,
UserOutline,
} from '@photonix/icons';
import { Avatar, Box, Button, Flex, IconButton, ListItem, Logo, NavItem, NavigationRail, SearchField, Stack, Text } from '@photonix/ultimate';
import { useState } from 'react';
export default function NavigationRailVariantApplicationExample() {
const [isRailCollapsed, setIsRailCollapsed] = useState(false);
const [isLogoHovered, setIsLogoHovered] = useState(false);
return (
<Flex h={768} w="100%" align="stretch" border="1px solid var(--border-neutral-tertiary)" borderRadius="2xs" overflow="hidden">
<NavigationRail
mode={isRailCollapsed ? 'collapsed' : 'expanded'}
showFooterDivider={false}
header={
<Stack direction="column" gap="sm" align="stretch">
<Flex align="center" justify="between" w="100%">
<Box
display="flex"
style={{ paddingLeft: isRailCollapsed ? '0' : '12px', transition: 'padding-left 300ms cubic-bezier(0.2, 0, 0, 1)' }}
onMouseEnter={() => isRailCollapsed && setIsLogoHovered(true)}
onMouseLeave={() => setIsLogoHovered(false)}
onClick={isRailCollapsed ? () => setIsRailCollapsed(false) : undefined}
role={isRailCollapsed ? 'button' : undefined}
>
{isRailCollapsed && isLogoHovered ? (
<IconButton
icon={<SideBarExpandOutline size={24} />}
variant="tertiary"
size="large"
aria-label="Expand"
onClick={() => setIsRailCollapsed(false)}
/>
) : (
<Logo height={48} format={isRailCollapsed ? 'icon' : 'full'} />
)}
</Box>
{!isRailCollapsed && (
<IconButton
icon={<SideBarCollapseOutline size={24} />}
variant="tertiary"
size="large"
aria-label="Collapse"
onClick={() => setIsRailCollapsed(true)}
/>
)}
</Flex>
<Box
display="flex"
w={isRailCollapsed ? 48 : '100%'}
style={{ transition: 'width 300ms cubic-bezier(0.2, 0, 0, 1)' }}
role="button"
onClick={isRailCollapsed ? () => setIsRailCollapsed(false) : undefined}
>
<SearchField
placeholder={isRailCollapsed ? '' : 'Quick find...'}
style={{
width: '100%',
padding: isRailCollapsed ? '0 12px' : undefined,
justifyContent: 'flex-start',
cursor: isRailCollapsed ? 'pointer' : 'text',
transition: 'all 300ms cubic-bezier(0.2, 0, 0, 1)',
height: isRailCollapsed ? '48px' : undefined,
}}
/>
</Box>
</Stack>
}
footer={
<Stack direction="column" gap="sm" align={isRailCollapsed ? 'center' : 'stretch'}>
{!isRailCollapsed && (
<Box p="sm" bg="secondary" borderRadius="sm">
<Text variant="label-lg" color="primary" style={{ marginBottom: 'var(--space-4xs)' }}>Upgrade Plan</Text>
<Text variant="body-sm" color="secondary" style={{ marginBottom: 'var(--space-xs)' }}>
Unlock features.
</Text>
<Button variant="primary" size="small" isFullWidth>Upgrade</Button>
</Box>
)}
{isRailCollapsed ? (
<Avatar size="40" name="Alex Smith" style={{ marginBottom: '12px' }} />
) : (
<ListItem
content="Alex Smith"
description="Pro Member"
leadingType="avatar"
avatarName="Alex Smith"
style={{ backgroundColor: 'var(--surface-neutral-on-surface)', borderRadius: 'var(--radius-sm)' }}
/>
)}
</Stack>
}
>
<NavItem id="app1" label="Workspace" icon={<AppsOutline />} selected />
<NavItem id="app2" label="Documentation" icon={<DocumentOutline />} />
<NavItem id="app3" label="Team" icon={<UserOutline />} />
<NavItem id="app4" label="Experiments" icon={<SparklesOutline />} />
</NavigationRail>
</Flex>
);
}Nested Items
Navigation items can contain children to support deeper tree structures.
Nested Items
"use client";
import { AppsOutline, CalendarOutline, OptionOutline } from '@photonix/icons';
import { Box, Flex, NavGroup, NavItem, NavigationRail } from '@photonix/ultimate';
export default function NavigationRailVariantNestedExample() {
return (
<Flex h={768} w="100%" align="stretch" border="1px solid var(--border-neutral-tertiary)" borderRadius="2xs" overflow="hidden">
<NavigationRail>
<NavGroup label="Projects">
<NavItem id="n1" label="Mobile App" icon={<AppsOutline />} selected />
<NavItem
id="n2"
label="Cloud Infrastructure"
icon={<CalendarOutline />}
children={[
{ id: 'n2-1', label: 'Networking', icon: <OptionOutline size={20} /> },
{ id: 'n2-2', label: 'Storage', icon: <OptionOutline size={20} /> },
{ id: 'n2-3', label: 'Clusters', icon: <OptionOutline size={20} /> },
]}
/>
<NavItem id="n3" label="Website" icon={<AppsOutline />} />
</NavGroup>
</NavigationRail>
</Flex>
);
}Floating Style
Use the floating prop to add shadow and border.
Floating Rail Content
Floating Style
"use client";
import { AppsOutline, DocumentOutline, SparklesOutline } from '@photonix/icons';
import { Box, Flex, Heading, Logo, NavGroup, NavItem, NavigationRail } from '@photonix/ultimate';
export default function NavigationRailVariantFloatingExample() {
return (
<Flex h={768} w="100%" bg="tertiary" align="stretch" p="md">
<NavigationRail floating header={<Logo height={48} />}>
<NavGroup label="Projects">
<NavItem id="f1" label="Development" icon={<AppsOutline />} selected />
<NavItem id="f2" label="Documentation" icon={<DocumentOutline />} />
<NavItem id="f3" label="Analysis" icon={<SparklesOutline />} />
</NavGroup>
</NavigationRail>
<Box flex={1} p="md">
<Heading size="title-md">Floating Rail Content</Heading>
</Box>
</Flex>
);
}Text Only
NavItems can render without icons for minimalist layouts.
Text Only
"use client";
import { Box, Flex, NavGroup, NavItem, NavigationRail } from '@photonix/ultimate';
export default function NavigationRailVariantNoIconsExample() {
return (
<Flex h={768} w="100%" align="stretch" border="1px solid var(--border-neutral-tertiary)" borderRadius="2xs" overflow="hidden">
<NavigationRail>
<NavGroup label="Resources">
<NavItem id="t1" label="Overview" selected />
<NavItem id="t2" label="Documentation" />
<NavItem id="t3" label="Community Feedback" />
<NavItem id="t4" label="Global Statistics" />
</NavGroup>
</NavigationRail>
</Flex>
);
}Small Size
Use smaller group and item sizing while keeping full navigation behavior.
Small Size
"use client";
import { AppsOutline, DocumentOutline, OptionOutline, SparklesOutline } from '@photonix/icons';
import { Box, Flex, NavGroup, NavItem, NavigationRail } from '@photonix/ultimate';
export default function NavigationRailVariantSmallExample() {
return (
<Flex h={768} w="100%" align="stretch" border="1px solid var(--border-neutral-tertiary)" borderRadius="2xs" overflow="hidden">
<NavigationRail mode="expanded" expandedWidth={256}>
<NavGroup label="Main" expanded size="sm">
<NavItem id="sm-home" label="Home" icon={<AppsOutline size={20} />} size="sm" selected />
<NavItem id="sm-docs" label="Documents" icon={<DocumentOutline size={20} />} size="sm" badge={3} />
<NavItem
id="sm-favorites"
label="Favorites"
icon={<SparklesOutline size={20} />}
size="sm"
children={[
{ id: 'sm-photos', label: 'Photos', icon: <OptionOutline size={20} />, size: 'sm' },
{ id: 'sm-videos', label: 'Videos', icon: <OptionOutline size={20} />, size: 'sm', disabled: true },
]}
/>
</NavGroup>
<NavGroup label="Settings" size="sm" badge>
<NavItem id="sm-general" label="General" icon={<OptionOutline size={20} />} size="sm" />
<NavItem id="sm-disabled" label="Disabled Item" icon={<OptionOutline size={20} />} size="sm" disabled />
</NavGroup>
</NavigationRail>
</Flex>
);
}On this page
Preview
Component API
Variants
Collapsed mode
With Groups
Application Structure
Nested Items (Level 2)
Floating Style
Text Only
Small Size