Photonix

NavigationRail

A premium side navigation container designed for desktops. It balances high-level navigation with detailed content groups.

Preview

Application content area

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
Photonix UI - React Components, Templates & Figma Design System