Tabs

Tabs organize content into multiple sections that users can navigate between. The component supports various visual styles, orientations, and interactive behaviors while maintaining accessibility standards.

Basics

Render the default tabs experience with inline content and a short caption explaining the pattern.

Loading demo…

import

 

{

 

Block

,

 

Tabs

,

 

Text

 

}

 

from

 

'@platform-blocks/react-ui-library'

;

 

const

 

ITEMS

 

=

 

[

  

{

    key

:

 

'overview'

,

    label

:

 

'Overview'

,

    content

:

 

<Text

>

High

-

level summary and entry point

.

</Text

>

  

}

,

  

{

    key

:

 

'details'

,

    label

:

 

'Details'

,

    content

:

 

<Text

>

Deeper

dive into metrics and configuration

.

</Text

>

  

}

,

  

{

    key

:

 

'activity'

,

    label

:

 

'Activity'

,

    content

:

 

<Text

>

Recent

events

,

tasks

,

and notifications

.

</Text

>

  

}

]

;

 

export

 

function

 

Demo

(

)

 

{

  

return

 

(

    

<Block

>

      

<Tabs

 

items

=

{

ITEMS

}

 

/>

      

<Text

 

variant

=

"small"

 

color

=

"muted"

>

        

Tabs

render inline content directly below the active trigger by

default

.

      

</Text

>

    

</Block

>

  

)

;

}

Animated transitions

Demonstrates motion-enabled tabs using the animated flag and custom duration to smooth the switch between panels.

Loading demo…

import

 

{

 

Block

,

 

Tabs

,

 

Text

 

}

 

from

 

'@platform-blocks/react-ui-library'

;

 

const

 

ITEMS

 

=

 

[

  

{

    key

:

 

'home'

,

    label

:

 

'Home'

,

    content

:

 

(

      

<Block

>

        

<Text

 

weight

=

"medium"

>

Welcome

back

</Text

>

        

<Text

 

color

=

"muted"

>

          

Animated

transitions ease between dashboard sections and reinforce context shifts

.

        

</Text

>

      

</Block

>

    

)

  

}

,

  

{

    key

:

 

'analytics'

,

    label

:

 

'Analytics'

,

    content

:

 

(

      

<Block

>

        

<Text

 

weight

=

"medium"

>

Analytics

overview

</Text

>

        

<Text

 

color

=

"muted"

>

          

Surface

key charts and

KPIs

 

while

the motion guides attention to

new

content

.

        

</Text

>

      

</Block

>

    

)

  

}

,

  

{

    key

:

 

'settings'

,

    label

:

 

'Settings'

,

    content

:

 

(

      

<Block

>

        

<Text

 

weight

=

"medium"

>

Account

settings

</Text

>

        

<Text

 

color

=

"muted"

>

          

Manage

notifications

,

billing

,

and other preferences without abrupt content swaps

.

        

</Text

>

      

</Block

>

    

)

  

}

]

;

 

export

 

function

 

Demo

(

)

 

{

  

return

 

(

    

<Block

>

      

<Tabs

        

variant

=

"line"

        animated

        

animationDuration

=

{

250

}

        

items

=

{

ITEMS

}

      

/>

      

<Text

 

variant

=

"small"

 

color

=

"muted"

>

        

Enable

 

`animated`

to add motion and use

`animationDuration`

to moderate the easing speed

.

      

</Text

>

    

</Block

>

  

)

;

}

Disabled tabs

Show how to disable a tab while capturing interaction attempts through onDisabledTabPress for auditing or messaging.

Loading demo…

import

 

{

useState

}

 

from

 

'react'

;

import

 

{

 

Block

,

 

Tabs

,

 

Text

,

useTheme

}

 

from

 

'@platform-blocks/react-ui-library'

;

 

const

 

PANELS

 

=

 

[

  

{

    key

:

 

'overview'

,

    label

:

 

'Overview'

,

    body

:

 

'High-level snapshot of product activity and health.'

  

}

,

  

{

    key

:

 

'analytics'

,

    label

:

 

'Analytics'

,

    body

:

 

'Dive into usage metrics, adoption trends, and retention.'

  

}

,

  

{

    key

:

 

'billing'

,

    label

:

 

'Billing'

,

    body

:

 

'Billing is temporarily disabled while invoices reconcile.'

,

    disabled

:

 

true

  

}

,

  

{

    key

:

 

'settings'

,

    label

:

 

'Settings'

,

    body

:

 

'Manage workspace preferences and security controls.'

  

}

]

;

 

export

 

function

 

Demo

(

)

 

{

  

const

theme

=

 

useTheme

(

)

;

  

const

 

[

activeTab

,

setActiveTab

]

 

=

 

useState

(

'overview'

)

;

  

const

 

[

lastAttempt

,

setLastAttempt

]

 

=

useState

<

string

 

|

 

null

>

(

null

)

;

 

  

return

 

(

    

<Block

>

      

<Tabs

        

activeTab

=

{

activeTab

}

        

onTabChange

=

{

(

tab

)

 

=>

 

{

          

setActiveTab

(

tab

)

;

          

setLastAttempt

(

null

)

;

        

}

}

        

onDisabledTabPress

=

{

(

key

)

 

=>

 

{

          

const

label

=

 

PANELS

.

find

(

(

panel

)

 

=>

panel

.

key

===

key

)

?

.

label

??

key

;

          

setLastAttempt

(

`${label} is currently disabled.`

)

;

        

}

}

        

variant

=

"line"

        

size

=

"md"

        

items

=

{

PANELS

.

map

(

(

{

body

,

 

.

.

.

panel

}

)

 

=>

 

(

{

          

.

.

.

panel

,

          content

:

 

(

            

<Block

 

bg

=

{

theme

.

backgrounds

.

surface

}

 

borderColor

=

{

theme

.

backgrounds

.

border

}

 

radius

=

"lg"

 

p

=

"md"

>

              

<Text

>

{

body

}

</Text

>

            

</Block

>

          

)

        

}

)

)

}

      

/>

      

<Text

 

variant

=

"small"

 

color

=

"muted"

>

        

Disable

sensitive tabs

while

keeping the

`onDisabledTabPress`

callback to track attempted access

.

        

{

lastAttempt

?

 

` ${lastAttempt}`

 

:

 

''

}

      

</Text

>

    

</Block

>

  

)

;

}

Controlled state

Demonstrates controlled tabs that surface the active label and rely on external state updates via onTabChange.

Loading demo…

import

 

{

useState

}

 

from

 

'react'

;

import

 

{

 

Block

,

 

Tabs

,

 

Text

 

}

 

from

 

'@platform-blocks/react-ui-library'

;

 

const

 

ITEMS

 

=

 

[

  

{

    key

:

 

'dashboard'

,

    label

:

 

'🏠 Dashboard'

,

    content

:

 

<Text

>

Monitor

analytics across teams and products

.

</Text

>

  

}

,

  

{

    key

:

 

'settings'

,

    label

:

 

'⚙️ Settings'

,

    content

:

 

<Text

>

Configure

notifications

,

permissions

,

and integrations

.

</Text

>

  

}

,

  

{

    key

:

 

'profile'

,

    label

:

 

'👤 Profile'

,

    content

:

 

<Text

>

Review

contact details

,

roles

,

and security options

.

</Text

>

  

}

]

;

 

export

 

function

 

Demo

(

)

 

{

  

const

 

[

activeTab

,

setActiveTab

]

 

=

 

useState

(

'dashboard'

)

;

  

const

activeLabel

=

 

ITEMS

.

find

(

(

item

)

 

=>

item

.

key

===

activeTab

)

?

.

label

??

activeTab

;

 

  

return

 

(

    

<Block

>

      

<Tabs

 

activeTab

=

{

activeTab

}

 

onTabChange

=

{

setActiveTab

}

 

items

=

{

ITEMS

}

 

/>

      

<Text

 

variant

=

"small"

 

color

=

"muted"

>

        

Active

tab

:

 

{

activeLabel

}

      

</Text

>

    

</Block

>

  

)

;

}

Location

Switch tab placement between start and end to position triggers above or below the associated content.

Loading demo…

import

 

{

 

Block

,

 

Tabs

,

 

Text

 

}

 

from

 

'@platform-blocks/react-ui-library'

;

 

type

 

Location

 

=

 

'start'

 

|

 

'end'

;

 

const

 

SECTIONS

:

 

Array

<

{

label

:

 

string

;

location

:

 

Location

;

helper

:

 

string

 

}

>

 

=

 

[

  

{

    label

:

 

'Tabs above content (start)'

,

    location

:

 

'start'

,

    helper

:

 

'Default placement keeps triggers directly above the active view.'

  

}

,

  

{

    label

:

 

'Tabs below content (end)'

,

    location

:

 

'end'

,

    helper

:

 

'Use end placement when the content should lead and controls follow.'

  

}

]

;

 

const

buildItems

=

 

(

location

:

 

Location

)

 

=>

 

[

  

{

    key

:

 

'home'

,

    label

:

 

'Home'

,

    content

:

 

(

      

<Text

>

        

Home

content rendered with tabs

{

location

===

 

'start'

 

?

 

'above'

 

:

 

'below'

}

the panel

.

      

</Text

>

    

)

  

}

,

  

{

    key

:

 

'settings'

,

    label

:

 

'Settings'

,

    content

:

 

(

      

<Text

>

        

Update

configurations

while

keeping the tabs

{

location

===

 

'start'

 

?

 

'up top'

 

:

 

'after the details'

}

.

      

</Text

>

    

)

  

}

,

  

{

    key

:

 

'profile'

,

    label

:

 

'Profile'

,

    content

:

 

(

      

<Text

>

        

Profile

information with navigation

{

location

===

 

'start'

 

?

 

'leading into'

 

:

 

'following'

}

the content

.

      

</Text

>

    

)

  

}

]

;

 

export

 

function

 

Demo

(

)

 

{

  

return

 

(

    

<Block

>

      

{

SECTIONS

.

map

(

(

{

label

,

location

,

helper

}

)

 

=>

 

(

        

<Block

 

key

=

{

location

}

>

          

<Text

 

weight

=

"medium"

>

{

label

}

</Text

>

          

<Tabs

 

variant

=

"line"

 

location

=

{

location

}

 

items

=

{

buildItems

(

location

)

}

 

/>

          

<Text

 

variant

=

"small"

 

color

=

"muted"

>

            

{

helper

}

          

</Text

>

        

</Block

>

      

)

)

}

    

</Block

>

  

)

;

}

Demonstrates navigationOnly tabs that render the triggers separately while a custom container handles the content region.

Loading demo…

import

 

{

useMemo

,

useState

}

 

from

 

'react'

;

import

 

{

 

Block

,

 

Tabs

,

 

Text

,

useTheme

}

 

from

 

'@platform-blocks/react-ui-library'

;

 

const

NAV_ITEMS

=

 

[

  

{

key

:

 

'home'

,

label

:

 

'Home'

 

}

,

  

{

key

:

 

'products'

,

label

:

 

'Products'

 

}

,

  

{

key

:

 

'about'

,

label

:

 

'About'

 

}

,

  

{

key

:

 

'contact'

,

label

:

 

'Contact'

 

}

]

as

const

;

 

const

CONTENT_COPY

:

 

Record

<

typeof NAV_ITEMS

[

number

]

[

'key'

]

,

 

string

>

 

=

 

{

  home

:

 

'Welcome back! Navigation only mode keeps the tab strip separated from the view.'

,

  products

:

 

'Highlight product cards, filters, or category grids below the navigation.'

,

  about

:

 

'Share the company story, values, and milestones alongside persistent tabs.'

,

  contact

:

 

'Surface support channels and locations while the navigation stays fixed.'

}

;

 

export

 

function

 

Demo

(

)

 

{

  

const

theme

=

 

useTheme

(

)

;

  

const

 

[

activeTab

,

setActiveTab

]

 

=

useState

<

typeof NAV_ITEMS

[

number

]

[

'key'

]

>

(

'home'

)

;

 

  

const

items

=

 

useMemo

(

    

(

)

 

=>

NAV_ITEMS

.

map

(

(

{

key

,

label

}

)

 

=>

 

(

{

key

,

label

,

content

:

 

null

 

}

)

)

,

    

[

]

  

)

;

 

  

return

 

(

    

<Block

>

      

<Tabs

        

items

=

{

items

}

        

activeTab

=

{

activeTab

}

        

onTabChange

=

{

(

tabKey

)

 

=>

 

setActiveTab

(

tabKey as typeof NAV_ITEMS

[

number

]

[

'key'

]

)

}

        

variant

=

"chip"

        navigationOnly

      

/>

      

<Block

 

bg

=

{

theme

.

backgrounds

.

surface

}

 

borderColor

=

{

theme

.

backgrounds

.

border

}

 

radius

=

"lg"

 

p

=

"lg"

>

        

<Text

>

{

CONTENT_COPY

[

activeTab

]

}

</Text

>

      

</Block

>

      

<Text

 

variant

=

"small"

 

color

=

"muted"

>

        

`navigationOnly`

renders just the triggers so you can manage layout and transitions

for

the content area yourself

.

      

</Text

>

    

</Block

>

  

)

;

}

Orientation

Compare horizontal and vertical tab lists to understand how orientation influences page layout.

Loading demo…

import

 

{

 

Block

,

 

Tabs

,

 

Text

 

}

 

from

 

'@platform-blocks/react-ui-library'

;

 

type

 

Orientation

 

=

 

'horizontal'

 

|

 

'vertical'

;

 

const

buildItems

=

 

(

orientation

:

 

Orientation

)

 

=>

 

[

  

{

    key

:

 

'general'

,

    label

:

 

'General'

,

    content

:

 

(

      

<Text

>

        

Broad

overview content rendered with a

{

orientation

}

tab list

.

      

</Text

>

    

)

  

}

,

  

{

    key

:

 

'security'

,

    label

:

 

'Security'

,

    content

:

 

(

      

<Text

>

        

Security

controls and permissions laid out

for

a

{

orientation

}

arrangement

.

      

</Text

>

    

)

  

}

,

  

{

    key

:

 

'notifications'

,

    label

:

 

'Notifications'

,

    content

:

 

(

      

<Text

>

        

Configure

alerts and digests with triggers stacked

{

orientation

===

 

'vertical'

 

?

 

'in a column'

 

:

 

'in a row'

}

.

      

</Text

>

    

)

  

}

]

;

 

const

 

ORIENTATIONS

:

 

Array

<

{

label

:

 

string

;

orientation

:

 

Orientation

;

helper

:

 

string

 

}

>

 

=

 

[

  

{

    label

:

 

'Horizontal orientation'

,

    orientation

:

 

'horizontal'

,

    helper

:

 

'Default layout presents tabs in a row for top-level navigation.'

  

}

,

  

{

    label

:

 

'Vertical orientation'

,

    orientation

:

 

'vertical'

,

    helper

:

 

'Vertical tab lists are ideal for settings sidebars and dense menus.'

  

}

]

;

 

export

 

function

 

Demo

(

)

 

{

  

return

 

(

    

<Block

>

      

{

ORIENTATIONS

.

map

(

(

{

label

,

orientation

,

helper

}

)

 

=>

 

(

        

<Block

 

key

=

{

orientation

}

>

          

<Text

 

weight

=

"medium"

>

{

label

}

</Text

>

          

<Tabs

 

orientation

=

{

orientation

}

 

items

=

{

buildItems

(

orientation

)

}

 

/>

          

<Text

 

variant

=

"small"

 

color

=

"muted"

>

            

{

helper

}

          

</Text

>

        

</Block

>

      

)

)

}

    

</Block

>

  

)

;

}

Variants

Compare the line, chip, and folder visual variants to match tabs with different design aesthetics.

Loading demo…

import

 

type

 

{

 

ComponentProps

 

}

 

from

 

'react'

;

import

 

{

 

Block

,

 

Tabs

,

 

Text

 

}

 

from

 

'@platform-blocks/react-ui-library'

;

 

type

 

Variant

 

=

 

NonNullable

<ComponentProps

<

typeof

Tabs

>

[

'variant'

]

>

;

 

const

VARIANT_DEMOS

:

 

Array

<

{

  heading

:

 

string

;

  variant

:

 

Variant

;

  helper

:

 

string

;

  items

:

 

Array

<

{

key

:

 

string

;

label

:

 

string

;

description

:

 

string

 

}

>

;

}

>

 

=

 

[

  

{

    heading

:

 

'Line variant'

,

    variant

:

 

'line'

,

    helper

:

 

'Minimal underline style aligns with primary navigation patterns.'

,

    items

:

 

[

      

{

key

:

 

'documents'

,

label

:

 

'Documents'

,

description

:

 

'Underline emphasizes the active document view.'

 

}

,

      

{

key

:

 

'images'

,

label

:

 

'Images'

,

description

:

 

'Great for media browsers with subtle hierarchy.'

 

}

,

      

{

key

:

 

'videos'

,

label

:

 

'Videos'

,

description

:

 

'Pairs well with narrow tab bars and dense content.'

 

}

    

]

  

}

,

  

{

    heading

:

 

'Chip variant'

,

    variant

:

 

'chip'

,

    helper

:

 

'Rounded pills feel tactile and work well for filters or secondary navigation.'

,

    items

:

 

[

      

{

key

:

 

'overview'

,

label

:

 

'Overview'

,

description

:

 

'Pills highlight the selected state with a filled background.'

 

}

,

      

{

key

:

 

'details'

,

label

:

 

'Details'

,

description

:

 

'Suitable for segmented controls or inline filters.'

 

}

,

      

{

key

:

 

'settings'

,

label

:

 

'Settings'

,

description

:

 

'Works nicely for preference toggles.'

 

}

    

]

  

}

,

  

{

    heading

:

 

'Folder variant'

,

    variant

:

 

'folder'

,

    helper

:

 

'Raised folder styling evokes classic tabbed interfaces.'

,

    items

:

 

[

      

{

key

:

 

'overview-folder'

,

label

:

 

'Overview'

,

description

:

 

'Ideal for dashboards with nested content.'

 

}

,

      

{

key

:

 

'details-folder'

,

label

:

 

'Details'

,

description

:

 

'Tabs feel like document dividers for data-heavy views.'

 

}

,

      

{

key

:

 

'settings-folder'

,

label

:

 

'Settings'

,

description

:

 

'Keeps controls organized in admin interfaces.'

 

}

    

]

  

}

]

;

 

export

 

function

 

Demo

(

)

 

{

  

return

 

(

    

<Block

>

      

{

VARIANT_DEMOS

.

map

(

(

{

heading

,

variant

,

helper

,

items

}

)

 

=>

 

(

        

<Block

 

key

=

{

variant

}

>

          

<Text

 

weight

=

"medium"

>

{

heading

}

</Text

>

          

<Tabs

            

variant

=

{

variant

}

            

items

=

{

items

.

map

(

(

{

description

,

 

.

.

.

item

}

)

 

=>

 

(

{

              

.

.

.

item

,

              content

:

 

<Text

>

{

description

}

</Text

>

            

}

)

)

}

          

/>

          

<Text

 

variant

=

"small"

 

color

=

"muted"

>

            

{

helper

}

          

</Text

>

        

</Block

>

      

)

)

}

    

</Block

>

  

)

;

}

Scan to open this page on your phonereact-ui-library.com/components/Tabs

</>

react-ui-library

100+ accessible, themeable components that work seamlessly across iOS, Android, and Web.

A Platform Blocks product.