Tabs

Switch between different views
Import

Usage

Messages tab content
Settings tab content
Color
Variant
Radius
xs
sm
md
lg
xl
Orientation
import { Tabs } from '@mantine/core';
import { IconPhoto, IconMessageCircle, IconSettings } from '@tabler/icons-react';
function Demo() {
return (
<Tabs defaultValue="gallery">
<Tabs.List>
<Tabs.Tab value="gallery" icon={<IconPhoto size="0.8rem" />}>Gallery</Tabs.Tab>
<Tabs.Tab value="messages" icon={<IconMessageCircle size="0.8rem" />}>Messages</Tabs.Tab>
<Tabs.Tab value="settings" icon={<IconSettings size="0.8rem" />}>Settings</Tabs.Tab>
</Tabs.List>
<Tabs.Panel value="gallery" pt="xs">
Gallery tab content
</Tabs.Panel>
<Tabs.Panel value="messages" pt="xs">
Messages tab content
</Tabs.Panel>
<Tabs.Panel value="settings" pt="xs">
Settings tab content
</Tabs.Panel>
</Tabs>
);
}

Controlled Tabs

To control Tabs state provide value and onTabChange props:

import { useState } from 'react';
import { Tabs } from '@mantine/core';
function Demo() {
const [activeTab, setActiveTab] = useState<string | null>('first');
return (
<Tabs value={activeTab} onTabChange={setActiveTab}>
<Tabs.List>
<Tabs.Tab value="first">First tab</Tabs.Tab>
<Tabs.Tab value="second">Second tab</Tabs.Tab>
</Tabs.List>
<Tabs.Panel value="first">First panel</Tabs.Panel>
<Tabs.Panel value="second">Second panel</Tabs.Panel>
</Tabs>
);
}

Uncontrolled Tabs

If you do not need to subscribe to Tabs state changes use defaultValue:

import { Tabs } from '@mantine/core';
function Demo() {
return (
<Tabs defaultValue="first">
<Tabs.List>
<Tabs.Tab value="first">First tab</Tabs.Tab>
<Tabs.Tab value="second">Second tab</Tabs.Tab>
</Tabs.List>
<Tabs.Panel value="first">First panel</Tabs.Panel>
<Tabs.Panel value="second">Second panel</Tabs.Panel>
</Tabs>
);
}

Icon and right section

You can use any React node as icon and rightSection in Tabs.Tab component:

Change colors

To change colors of all tabs set color on Tabs component, to change color of the individual tab set color on Tabs.Tab. color should be a key of theme.colors:

First tab color is teal, it gets this value from context
Second tab color is blue, it gets this value from props, props have the priority and will override context value
import { Tabs } from '@mantine/core';
function Demo() {
return (
<Tabs color="teal" defaultValue="first">
<Tabs.List>
<Tabs.Tab value="first">Teal tab</Tabs.Tab>
<Tabs.Tab value="second" color="blue">
Blue tab
</Tabs.Tab>
</Tabs.List>
<Tabs.Panel value="first" pt="xs">
First tab color is teal, it gets this value from context
</Tabs.Panel>
<Tabs.Panel value="second" pt="xs">
Second tab color is blue, it gets this value from props, props have the priority and will
override context value
</Tabs.Panel>
</Tabs>
);
}

Tabs position

import { Tabs } from '@mantine/core';
function Demo() {
return (
<Tabs defaultValue="first">
<Tabs.List>
<Tabs.Tab value="first">First tab</Tabs.Tab>
<Tabs.Tab value="second">Second tab</Tabs.Tab>
<Tabs.Tab value="third">Third tab</Tabs.Tab>
</Tabs.List>
</Tabs>
);
}

To display tab on the opposite side, set margin-left to auto with ml="auto" prop:

import { Tabs } from '@mantine/core';
function Demo() {
return (
<Tabs defaultValue="chat">
<Tabs.List>
<Tabs.Tab value="chat">Chat</Tabs.Tab>
<Tabs.Tab value="gallery">Gallery</Tabs.Tab>
<Tabs.Tab value="settings">Settings</Tabs.Tab>
<Tabs.Tab value="account" ml="auto">
Account
</Tabs.Tab>
</Tabs.List>
</Tabs>
);
}

Inverted tabs

To make tabs inverted, place Tabs.Panel components before Tabs.List and add inverted prop to Tabs component:

Chat panel
Account panel
import { Tabs } from '@mantine/core';
function Demo() {
return (
<Tabs defaultValue="chat" inverted>
<Tabs.Panel value="chat" pb="xs">Chat panel</Tabs.Panel>
<Tabs.Panel value="gallery" pb="xs">Gallery panel</Tabs.Panel>
<Tabs.Panel value="account" pb="xs">Account panel</Tabs.Panel>
<Tabs.List>
<Tabs.Tab value="chat">Chat</Tabs.Tab>
<Tabs.Tab value="gallery">Gallery</Tabs.Tab>
<Tabs.Tab value="account">Account</Tabs.Tab>
</Tabs.List>
</Tabs>
);
}

Vertical tabs placement

To change placement of Tabs.List in vertical orientation set placement prop:

Messages tab content
Settings tab content
Placement
import { Tabs } from '@mantine/core';
function Demo() {
return (
<Tabs defaultValue="gallery" orientation="vertical">
<Tabs.List>
<Tabs.Tab value="gallery">Gallery</Tabs.Tab>
<Tabs.Tab value="messages">Messages</Tabs.Tab>
<Tabs.Tab value="settings">Settings</Tabs.Tab>
</Tabs.List>
<Tabs.Panel value="gallery">Gallery tab content</Tabs.Panel>
<Tabs.Panel value="messages">Messages tab content</Tabs.Panel>
<Tabs.Panel value="settings">Settings tab content</Tabs.Panel>
</Tabs>
);
}

Disabled tabs

Set disabled prop on Tabs.Tab component to disable tab. Disabled tab cannot be activated with mouse or keyboard, will be skipped when user navigates with arrow keys:

import { Tabs } from '@mantine/core';
function Demo() {
return (
<Tabs defaultValue="chat">
<Tabs.List>
<Tabs.Tab value="chat">Chat</Tabs.Tab>
<Tabs.Tab value="gallery">Gallery</Tabs.Tab>
<Tabs.Tab value="settings" disabled>
Settings
</Tabs.Tab>
<Tabs.Tab value="account">Account</Tabs.Tab>
</Tabs.List>
</Tabs>
);
}

Activation mode

By default, tabs are activated when user presses arrows and Home/End keys. To disable that set activateTabWithKeyboard={false} on Tabs component, then user will be able to deactivate active tab by clicking on it:

Chat panel
Account panel

Tab deactivation

By default, active cannot be deactivated. To allow that set allowTabDeactivation on Tabs component:

Chat panel
Account panel

Unmount inactive tabs

By default, inactive Tabs.Panel will stay mounted, to unmount inactive tabs, set keepMounted={false} on Tabs. This is useful when you want to render components that impact performance inside Tabs.Panel. Note that components that are rendered inside Tabs.Panel will reset their state on each mount (tab change).

import { Tabs } from '@mantine/core';
// Second tab panel will be mounted only when user activates second tab
function Demo() {
return (
<Tabs keepMounted={false} defaultValue="first">
<Tabs.List>
<Tabs.Tab value="first">First tab</Tabs.Tab>
<Tabs.Tab value="second">Second tab</Tabs.Tab>
</Tabs.List>
<Tabs.Panel value="first">First panel</Tabs.Panel>
<Tabs.Panel value="second">Second panel</Tabs.Panel>
</Tabs>
);
}

Unstyled Tabs

Set unstyled prop on Tabs component to remove all non-essential library styles.

Chat panel
Account panel

By doing so, you will be able to keep component behavior while providing your own styles with Styles API:

Get tab control ref

import { useRef } from 'react';
import { Tabs } from '@mantine/core';
function Demo() {
const secondTabRef = useRef<HTMLButtonElement>(null);
return (
<Tabs defaultValue="first">
<Tabs.List>
<Tabs.Tab value="first">First tab</Tabs.Tab>
<Tabs.Tab value="Second" ref={secondTabRef}>
Second tab
</Tabs.Tab>
<Tabs.Tab value="third">Third tab</Tabs.Tab>
</Tabs.List>
</Tabs>
);
}

Usage with react-router

<Route path="/tabs/:tabValue" element={<Demo />} />
import { useNavigate, useParams } from 'react-router-dom';
import { Tabs } from '@mantine/core';
function Demo() {
const navigate = useNavigate();
const { tabValue } = useParams();
return (
<Tabs value={tabValue} onTabChange={(value) => navigate(`/tabs/${value}`)}>
<Tabs.List>
<Tabs.Tab value="first">First tab</Tabs.Tab>
<Tabs.Tab value="second">Second tab</Tabs.Tab>
</Tabs.List>
</Tabs>
);
}

Usage with Next.js router

// For file /tabs/[activeTab].tsx
import { useRouter } from 'next/router';
import { Tabs } from '@mantine/core';
function Demo() {
const router = useRouter();
return (
<Tabs
value={router.query.activeTab as string}
onTabChange={(value) => router.push(`/tabs/${value}`)}
>
<Tabs.List>
<Tabs.Tab value="first">First tab</Tabs.Tab>
<Tabs.Tab value="second">Second tab</Tabs.Tab>
</Tabs.List>
</Tabs>
);
}

Accessibility

Tabs component follows WAI-ARIA recommendations on accessibility.

Notes

If you use Tabs.Tab without text content, for example, only with icon, then set aria-label:

import { Tabs } from '@mantine/core';
import { IconCoin } from '@tabler/icon';
function Demo() {
return (
<Tabs defaultValue="chat">
<Tabs.List>
{/* aria-label is not required, tab is labelled by children */}
<Tabs.Tab value="chat">Chat</Tabs.Tab>
{/* aria-label is required, tab is not labelled by children */}
<Tabs.Tab icon={<IconCoin size={14} />} value="money" aria-label="Get money" />
</Tabs.List>
</Tabs>
);
}

To set tabs list label, set aria-label on Tabs.List component, it will be announced by screen reader:

import { Tabs } from '@mantine/core';
function Demo() {
return (
<Tabs defaultValue="recent">
{/* Tabs.List aria-label will be announced when tab is focused for the first time */}
<Tabs.List aria-label="Chats">
<Tabs.Tab value="recent">Most recent</Tabs.Tab>
<Tabs.Tab value="recent">Unanswered</Tabs.Tab>
<Tabs.Tab value="archived">Archived</Tabs.Tab>
</Tabs.List>
</Tabs>
);
}

Keyboard interactions

KeyDescriptionCondition
ArrowRightFocuses and activates next tab that is not disabledorientation="horizontal"
ArrowLeftFocuses and activates previous tab that is not disabledorientation="horizontal"
ArrowDownFocuses and activates next tab that is not disabledorientation="vertical"
ArrowUpFocuses and activates previous tab that is not disabledorientation="vertical"
HomeFocuses and activates first tab
EndFocuses and activates last tab

Tabs component props

NameTypeDescription
activateTabWithKeyboard
boolean
Determines whether tab should be activated with arrow key press, defaults to true
allowTabDeactivation
boolean
Determines whether tab can be deactivated, defaults to false
children *
ReactNode
Tabs content
color
MantineColor
Key of theme.colors
defaultValue
string
Default value for uncontrolled component
id
string
Base id, used to generate ids that connect labels with controls, by default generated randomly
inverted
boolean
Determines whether tabs should have inverted styles
keepMounted
boolean
If set to false, Tabs.Panel content will not stay mounted when tab is not active
loop
boolean
Determines whether arrow key presses should loop though items (first to last and last to first)
onTabChange
(value: string) => void
Callback for controlled component
orientation
"horizontal" | "vertical"
Tabs orientation, vertical or horizontal
placement
"left" | "right"
Tabs.List placement relative to Tabs.Panel, applicable only for orientation="vertical", left by default
radius
number | "xs" | "sm" | "md" | "lg" | "xl"
Key of theme.radius or any valid CSS value to set border-radius, theme.defaultRadius by default
value
string
Value for controlled component
variant
TabsVariant
Controls component visuals

Tabs.Tab component props

NameTypeDescription
children
ReactNode
Tab label
color
MantineColor
Key of theme.colors
icon
ReactNode
Section of content displayed before label
rightSection
ReactNode
Section of content displayed after label
value *
string
Value that is used to connect Tab with associated panel

Tabs.List component props

NameTypeDescription
children *
ReactNode
<Tabs.Tab /> components
grow
boolean
Determines whether tabs should take the whole space
position
"left" | "right" | "center" | "apart"
Tabs alignment

Tabs.Panel component props

NameTypeDescription
children *
ReactNode
Panel content
value *
string
Value of associated control

Tabs component Styles API

NameStatic selectorDescription
root.mantine-Tabs-rootRoot element
tabsList.mantine-Tabs-tabsListControls list (Tabs.List component)
tab.mantine-Tabs-tabTab control (Tabs.Tab component)
tabRightSection.mantine-Tabs-tabRightSectionTab control right section
tabLabel.mantine-Tabs-tabLabelTab control label
tabIcon.mantine-Tabs-tabIconTab control icon
panel.mantine-Tabs-panelTab panel (Tabs.Panel component)