Skip to content

Latest commit

 

History

History
300 lines (228 loc) · 7.78 KB

Tabs.mdx

File metadata and controls

300 lines (228 loc) · 7.78 KB
group package title order slug category description componentPrefix props import source docs styles
mantine-core
@mantine/core
Tabs
1
/core/tabs/
navigation
Switch between different views
Tabs
Tabs
Tab
TabsList
TabsPanel
import { Tabs } from '@mantine/core';
mantine-core/src/Tabs/Tabs.tsx
core/Tabs.mdx
Tabs

import { TabsDemos } from '@mantine/demos';

Usage

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 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:

<Demo data={TabsDemos.icons} demoProps={{ toggle: true }} />

<Demo data={TabsDemos.rightSection} demoProps={{ toggle: true }} />

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:

Tabs position

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

Inverted tabs

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

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:

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:

<Demo data={TabsDemos.keyboardActivation} demoProps={{ toggle: true }} />

Tab deactivation

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

<Demo data={TabsDemos.deactivate} demoProps={{ toggle: true }} />

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.

<Demo data={TabsDemos.unstyled} demoProps={{ toggle: true }} />

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

<Demo data={TabsDemos.stylesApi} demoProps={{ toggle: true }} />

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

<KeyboardEventsTable data={[ { key: 'ArrowRight', description: 'Focuses and activates next tab that is not disabled', condition: 'orientation="horizontal"', }, { key: 'ArrowLeft', description: 'Focuses and activates previous tab that is not disabled', condition: 'orientation="horizontal"', }, { key: 'ArrowDown', description: 'Focuses and activates next tab that is not disabled', condition: 'orientation="vertical"', }, { key: 'ArrowUp', description: 'Focuses and activates previous tab that is not disabled', condition: 'orientation="vertical"', }, { key: 'Home', description: 'Focuses and activates first tab' }, { key: 'End', description: 'Focuses and activates last tab' }, ]} />