Skip to content
Harness Design System Harness Design System Harness Design System

Tabs

beta

The Tabs component provides a way to organize content into multiple panels, with each panel being associated with a tab trigger. It supports both regular tabs and navigation tabs that integrate with your router.

It can be composed with several subcomponents such as Tabs.Root, Tabs.NavRoot, Tabs.List, Tabs.Trigger, and Tabs.Content to offer a structured and customizable interface.

Usage

import { Tabs } from "@harnessio/ui/components";
//...
return (
<Tabs.Root defaultValue="general">
<Tabs.List>
<Tabs.Trigger value="general">General</Tabs.Trigger>
<Tabs.Trigger value="security">Security</Tabs.Trigger>
<Tabs.Trigger value="advanced">Advanced</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="general">
{/* General settings content */}
</Tabs.Content>
<Tabs.Content value="security">
{/* Security settings content */}
</Tabs.Content>
<Tabs.Content value="advanced">
{/* Advanced settings content */}
</Tabs.Content>
</Tabs.Root>
)

Anatomy

All parts of the Tabs component can be imported and composed as required.

// Regular Tabs
<Tabs.Root>
<Tabs.List>
<Tabs.Trigger />
</Tabs.List>
<Tabs.Content />
</Tabs.Root>
// Navigation Tabs
<Tabs.NavRoot>
<Tabs.List>
<Tabs.Trigger />
</Tabs.List>
</Tabs.NavRoot>

Variants

The Tabs component supports multiple visual variants that can be applied via the variant prop on Tabs.List.

With Icons

Tab triggers can include icons to enhance visual recognition and improve user experience.

With Logos

Tab triggers can display logos for brand-specific navigation or integration tabs.

With Counters

Tab triggers can display counter badges to show quantities or notifications.

Complex Children

When icons, logos, and counters aren’t sufficient, you can use custom children for more complex tab triggers.

The Tabs.NavRoot variant integrates with your router to create navigation-based tabs that update based on the current route.

Controlled Tabs

Both Tabs.Root and Tabs.NavRoot can be controlled by passing value and onValueChange props.

Custom Active Class

You can customize the active tab styling using the activeClassName prop on Tabs.List.

API Reference

Root

The Root component serves as the main container for regular tabs functionality. It manages the active tab state and provides context to child components.

<Tabs.Root
value={activeTab} // [OPTIONAL] controlled active tab value
onValueChange={onChange} // [OPTIONAL] callback when active tab changes
defaultValue="tab1" // [OPTIONAL] default active tab (uncontrolled)
>
{/* List and Content components */}
</Tabs.Root>
Prop
Required
Default
Type
defaultValuefalsestring
valuefalsestring
onValueChangefalse(value: string) => void
childrentrueReactNode

The NavRoot component serves as the main container for navigation-based tabs. It integrates with your router to update the active tab based on the current route.

<Tabs.NavRoot
value={activeRoute} // [OPTIONAL] controlled active route
onValueChange={navigate} // [OPTIONAL] callback when route changes
defaultValue="/home" // [OPTIONAL] default route
>
{/* List and optional Content components */}
</Tabs.NavRoot>
Prop
Required
Default
Type
valuefalsestring
onValueChangefalse(value: string) => void
defaultValuefalsestring
childrentrueReactNode

List

The List component is a container for tab triggers that handles layout and styling variants.

<Tabs.List
variant="underlined" // [OPTIONAL] visual variant
className="my-class" // [OPTIONAL] custom class
activeClassName="active" // [OPTIONAL] class for active tab
>
{/* Trigger components */}
</Tabs.List>
Prop
Required
Default
Type
classNamefalsestring
variantfalse'underlined''underlined' | 'overlined' | 'ghost' | 'outlined'
activeClassNamefalsestring
childrentrueReactNode

Trigger

The Trigger component represents an individual tab button or navigation link.

// Regular tab trigger
<Tabs.Trigger
value="tab1" // unique identifier for the tab
icon="dashboard" // [OPTIONAL] icon name
logo="github" // [OPTIONAL] logo name (mutually exclusive with icon)
counter={5} // [OPTIONAL] counter badge value
variant="underlined" // [OPTIONAL] override List variant
className="my-class" // [OPTIONAL] custom class
disabled // [OPTIONAL] disable the trigger
>
{/* Optional custom children */}
</Tabs.Trigger>
// Navigation tab trigger
<Tabs.Trigger
value="/path" // route path
linkProps={{ // [OPTIONAL] additional link properties
target: "_blank",
replace: true
}}
>
Navigation Tab
</Tabs.Trigger>
Prop
Required
Default
Type
classNamefalsestring
variantfalse'underlined' | 'overlined' | 'ghost' | 'outlined'
valuetruestring
iconfalsestring
logofalsestring
counterfalsenumber | null
disabledfalsefalseboolean
linkPropsfalseOmit<NavLinkProps, 'to'>
childrenfalseReactNode

Content

The Content component represents the panel content associated with a tab.

<Tabs.Content
value="tab1" // matches the Trigger value
className="my-class" // [OPTIONAL] custom class
>
{/* Panel content */}
</Tabs.Content>
Prop
Required
Default
Type
classNamefalsestring
valuetruestring
childrentrueReactNode

Best Practices

  1. Unique Values: Ensure each tab trigger has a unique value prop
  2. Default Selection: Always provide either a defaultValue or controlled value to ensure a tab is selected by default
  3. Accessible Labels: Use descriptive text for tab triggers to ensure good accessibility
  4. Icon Usage: Choose between icon or logo props - don’t use both on the same trigger
  5. Navigation Tabs: Use NavRoot when tabs represent different routes in your application
  6. Content Loading: Consider lazy loading tab content for better performance with heavy content
  7. Keyboard Navigation: The component supports standard keyboard navigation (Arrow keys, Home, End)