Navigation Bar - React
import { NavBar } from "@sky-uk/ui-core";
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| $appearance | string | default | The
|
| $fill | boolean | false | Dictates whether the NavBar proportionately fill the available space. This prop is responsive and can be used to set the $fill value at different breakpoints. |
| as | string | nav | The as prop determines the semantic element used for the component. nav is a standard navigation landmark, tabs is used for tabbed interfaces, and anchor is for anchor link navigation. |
| activeIndex | number | Controls which item is active using a zero-based index. Use this for a controlled NavBar. | |
| onItemChange | (index: number) => void | The onItemChange callback triggers when an item is changed, providing the index of the changed item as a number. This enables custom actions based on the specific item interaction. | |
| onItemTrigger | (nextIndex: number, currentIndex: number) => boolean | Promise<boolean> | The onItemTrigger callback is triggered when an item is triggered. It receives the index of the item that is being triggered and the index of the currently active item. This callback can return a boolean or a Promise that resolves to a boolean to allow or prevent the activation from proceeding. |
NavBar.Item
| Prop | Type | Default | Description |
|---|---|---|---|
| $active | boolean | Sets the initially active item when the NavBar is uncontrolled. | |
| $hover | boolean | Displays the item in its hover state. | |
| $focused | boolean | Displays the item in its focused state. |
Basic NavBar
<NavBar> <NavBar.Item href="#"> One </NavBar.Item> <NavBar.Item href="#"> Two </NavBar.Item> <NavBar.Item href="#"> Three </NavBar.Item> <NavBar.Item href="#"> Four </NavBar.Item> </NavBar>
Page Navigation
NavBar can be used for page navigation by passing href props to NavBar.Item. In this example, the component is rendered as a nav element containing links to different pages.
For accessibility, set aria-current="page" on the active item. This indicates to users that they are on the page of the current nav item.
() => { const [activeIndex, setActiveIndex] = React.useState(0); const navItems = [ { label: "Home", href: "https://www.sky.com" }, { label: "Watch", href: "https://www.sky.com/watch" }, { label: "TV", href: "https://www.sky.com/tv" }, { label: "Glass", href: "https://www.sky.com/glass" }, { label: "Broadband", href: "https://www.sky.com/broadband" }, { label: "Mobile", href: "https://www.sky.com/shop/mobile" }, ]; return ( <NavBar activeIndex={activeIndex} onItemChange={setActiveIndex}> {navItems.map((item, idx) => ( <NavBar.Item key={item.label} href={item.href} target="_blank" rel="noopener" aria-current={activeIndex === idx ? "page" : undefined} > {item.label} </NavBar.Item> ))} </NavBar> ); }
Router Components
Use the component prop when you want NavBar.Item to render a framework-agnostic routing component such as React Router Link or Next.js Link.
This keeps the NavBar behavior the same while letting the routing component control navigation.
import { Link } from "react-router-dom";import NextLink from "next/link";<NavBar><NavBar.Item component={Link} to="/dashboard">Dashboard</NavBar.Item><NavBar.Item component={NextLink} href="/account">Account</NavBar.Item><NavBar.Item href="/support">Support</NavBar.Item></NavBar>;
In-Page Navigation
NavBar can be used for in-page anchor navigation by setting the as prop to "anchor" and providing href props that correspond to section IDs on the page. Clicking an item will smoothly scroll to the associated section. The active item updates based on the currently visible section as you scroll.
For accessibility, set aria-current="location" on the active item. This indicates that the active nav item is in view.
Tab Style Navigation
NavBar can be used as a tabs bar by setting the as prop to "tabs". In this mode, the component's semantics change: it renders as a div with role="tablist", and each NavBar.Item receives role=tab. In this example, clicking on a tab updates the active state and displays corresponding content below the NavBar.
For accessibility:
- Set
aria-selected="true"on the active tab item to indicate it is selected. - Each tab (
NavBar.Item) should have anaria-controlsattribute pointing to the ID of its associated tab panel. - Each tab panel (the content area with
role="tabpanel") should have anaria-labelledbyattribute pointing to the ID of its corresponding tab.
() => { const sections = [ { id: "overview", label: "Overview", color: "grey10" }, { id: "features", label: "Features", color: "grey20" }, { id: "pricing", label: "Pricing", color: "grey40" }, { id: "testimonials", label: "Testimonials", color: "grey50" }, { id: "faq", label: "FAQ", color: "grey70" }, { id: "contact", label: "Contact", color: "grey80" }, ]; const [activeItem, setActiveItem] = React.useState(sections[0].label); return ( <> <NavBar as="tabs"> {sections.map((section) => ( <NavBar.Item key={section.id} onClick={() => setActiveItem(section.label)} aria-selected={activeItem === section.label ? "true" : undefined} id={`tab-${section.id}`} aria-controls={`section-${section.id}`} > {section.label} </NavBar.Item> ))} </NavBar> {activeItem && ( <Box $alignItems="center" $bgColor={sections.find((s) => s.label === activeItem)?.color || "transparent"} $display="flex" $height="400px" $justifyContent="center" role="tabpanel" id={`section-${sections.find((s) => s.label === activeItem)?.id}`} aria-labelledby={`tab-${sections.find((s) => s.label === activeItem)?.id}`} > <Text $fontSize="display-2" $color="white"> {activeItem} </Text> </Box> )} </> ); }
Callbacks
onItemChange
The onItemChange callback is triggered when a item is changed. It receives the index of the changed item as a number. This allows you to determine which item was activated and perform additional actions or updates based on the selected item.
function Example(){ const [itemState, setItemState] = React.useState(0); const handleItemChange = index => { setItemState(index); }; return ( <Flex $flexDirection="column" $gap={5}> <Text>Current Tab index: {itemState}</Text> <NavBar onItemChange={handleItemChange}> <NavBar.Item $active>Video Doorbell</NavBar.Item> <NavBar.Item>Indoor Camera</NavBar.Item> <NavBar.Item>Motion & Contact Sensors</NavBar.Item> </NavBar> </Flex> ); }
onItemTrigger
The onItemTrigger callback requires a promise to be resolved before proceeding with navigation. In this example, when an item is clicked, a modal appears asking if the item change should proceed. Clicking Allow continues, Block cancels.
function Example(){ const [modalOpen, setModalOpen] = React.useState(false); const sections = [ { id: "broadband", label: "Broadband", icon: wifiHouseLinear, color: "grey50" }, { id: "tv", label: "TV", icon: tvLinear, color: "grey70" }, { id: "mobile", label: "Mobile", icon: mobileLinear, color: "grey80"}, ]; const resolveRef = React.useRef(); const onItemTrigger = () => { setModalOpen(true); return new Promise((resolve) => { resolveRef.current = resolve; }); }; const handleModalResult = (result) => { if (resolveRef.current) { resolveRef.current(result); resolveRef.current = undefined; } setModalOpen(false); }; const [activeItem, setActiveItem] = React.useState(sections[0].label); return ( <> <NavBar as='tabs' onItemTrigger={onItemTrigger}> {sections.map((section) => ( <NavBar.Item key={section.id} onClick={() => setActiveItem(section.label)} aria-selected={activeItem === section.label ? 'true' : undefined} > <Icon src={section.icon} $size={{ xs: 'medium', xl: 'large' }} /> {section.label} </NavBar.Item> ))} </NavBar> {activeItem && ( <Box $alignItems="center" $bgColor={sections.find((s) => s.label === activeItem)?.color || "transparent"} $display="flex" $height="400px" $justifyContent="center" role="tabpanel" id={`section-${sections.find((s) => s.label === activeItem)?.id}`} aria-labelledby={`tab-${sections.find((s) => s.label === activeItem)?.id}`} > <Text $fontSize='display-2' $color='white'> {activeItem} </Text> </Box> )} {modalOpen && ( <Modal onClose={() => handleModalResult(false)}> <Modal.Content> <Flex $flexDirection='column' $gap={4} $justifyContent='center' $alignItems='center' $width='400px' $height='250px' > <Text $fontSize='display-6'>Allow nav?</Text> <Flex $gap={2} $justifyContent='center'> <Button $variant='primary' onClick={() => handleModalResult(true)}> Allow </Button> <Button $variant='secondary' onClick={() => handleModalResult(false)}> Block </Button> </Flex> </Flex> </Modal.Content> </Modal> )} </> ); }
System Modifiers
The NavBar component supports the props applied using the following system modifiers: