HextaUI

Tabs

Alterne entre visões com um indicador que desliza até a aba ativa, como um controle segmentado ou um sublinhado, e listas que rolam quando transbordam.

Overview

Visitors are up 12% this week, mostly from search.

import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"

export function TabsDemo() {
  return (
    <Tabs defaultValue="overview" className="w-full max-w-md">
      <TabsList>
        <TabsTrigger value="overview">Overview</TabsTrigger>
        <TabsTrigger value="analytics">Analytics</TabsTrigger>
        <TabsTrigger value="reports">Reports</TabsTrigger>
      </TabsList>
      <TabsContent value="overview">
        <div className="rounded-xl border p-4 text-sm">
          <p className="font-medium">Overview</p>
          <p className="text-muted-foreground">
            Visitors are up 12% this week, mostly from search.
          </p>
        </div>
      </TabsContent>
      <TabsContent value="analytics">
        <div className="rounded-xl border p-4 text-sm">
          <p className="font-medium">Analytics</p>
          <p className="text-muted-foreground">
            Average session length is 4m 12s across 18,240 visits.
          </p>
        </div>
      </TabsContent>
      <TabsContent value="reports">
        <div className="rounded-xl border p-4 text-sm">
          <p className="font-medium">Reports</p>
          <p className="text-muted-foreground">
            Three scheduled reports go out on Monday.
          </p>
        </div>
      </TabsContent>
    </Tabs>
  )
}
pnpm dlx shadcn@latest add https://hextaui.com/r/tabs.json

Adiciona o componente, os tokens de tema do HextaUI e quaisquer componentes do HextaUI dos quais ele depende.

import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
<Tabs defaultValue="overview">
  <TabsList>
    <TabsTrigger value="overview">Overview</TabsTrigger>
    <TabsTrigger value="analytics">Analytics</TabsTrigger>
  </TabsList>
  <TabsContent value="overview">…</TabsContent>
  <TabsContent value="analytics">…</TabsContent>
</Tabs>

Um indicador desliza até a aba ativa e se redimensiona para caber nela, enquanto o conteúdo troca instantaneamente, então trocas frequentes nunca esperam por uma animação. O indicador é posicionado antes da hidratação da página, então nunca salta ao carregar.

Tabs
├── TabsList
│   └── TabsTrigger
└── TabsContent

Sublinhado

variant="line" em TabsList desliza um sublinhado em vez de uma pílula.

import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"

const tabs = ["Activity", "Pull requests", "Issues", "Settings"]

export function TabsLine() {
  return (
    <Tabs defaultValue="Activity" className="w-full max-w-md">
      <TabsList variant="line">
        {tabs.map((tab) => (
          <TabsTrigger key={tab} value={tab}>
            {tab}
          </TabsTrigger>
        ))}
      </TabsList>
      {tabs.map((tab) => (
        <TabsContent key={tab} value={tab}>
          <p className="py-2 text-sm text-muted-foreground">
            {tab} for this repository.
          </p>
        </TabsContent>
      ))}
    </Tabs>
  )
}

Muitas abas

Quando as abas não cabem, a lista rola para o lado, esmaece as bordas que têm mais a ver e rola a aba ativa ou com foco para a vista.

import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"

const months = [
  "January",
  "February",
  "March",
  "April",
  "May",
  "June",
  "July",
  "August",
  "September",
  "October",
  "November",
  "December",
]

export function TabsOverflow() {
  return (
    <Tabs defaultValue="September" className="w-full max-w-sm">
      <TabsList variant="line">
        {months.map((month) => (
          <TabsTrigger key={month} value={month}>
            {month}
          </TabsTrigger>
        ))}
      </TabsList>
    </Tabs>
  )
}

Muitas abas, segmentado

O estilo pill rola do mesmo jeito, mantendo sua trilha enquanto a aba escolhida permanece à vista.

import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"

const categories = [
  "All",
  "Design",
  "Engineering",
  "Marketing",
  "Sales",
  "Support",
  "Finance",
  "Legal",
  "Operations",
]

export function TabsOverflowSegmented() {
  return (
    <Tabs defaultValue="Finance" className="w-full max-w-xs">
      <TabsList>
        {categories.map((category) => (
          <TabsTrigger key={category} value={category}>
            {category}
          </TabsTrigger>
        ))}
      </TabsList>
    </Tabs>
  )
}

Ícones e contagens

Coloque ícones e badges dentro dos gatilhos.

import { IconCode, IconGitPullRequest, IconMessage } from "@tabler/icons-react"

import { Badge } from "@/components/ui/badge"
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"

export function TabsIcons() {
  return (
    <Tabs defaultValue="code">
      <TabsList variant="line">
        <TabsTrigger value="code">
          <IconCode />
          Code
        </TabsTrigger>
        <TabsTrigger value="pulls">
          <IconGitPullRequest />
          Pull requests
          <Badge>12</Badge>
        </TabsTrigger>
        <TabsTrigger value="discussions">
          <IconMessage />
          Discussions
        </TabsTrigger>
      </TabsList>
    </Tabs>
  )
}

Vertical

orientation="vertical" empilha as abas; o sublinhado vai para o lado.

import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"

const sections = [
  { value: "general", label: "General", text: "Name, avatar and language." },
  { value: "security", label: "Security", text: "Password and two-factor." },
  { value: "billing", label: "Billing", text: "Plan, invoices and payment." },
]

export function TabsVertical() {
  return (
    <Tabs
      defaultValue="general"
      orientation="vertical"
      className="w-full max-w-md"
    >
      <TabsList variant="line">
        {sections.map((section) => (
          <TabsTrigger key={section.value} value={section.value}>
            {section.label}
          </TabsTrigger>
        ))}
      </TabsList>
      {sections.map((section) => (
        <TabsContent key={section.value} value={section.value}>
          <div className="flex flex-col gap-1 py-2 text-sm">
            <p className="font-medium">{section.label}</p>
            <p className="text-muted-foreground">{section.text}</p>
          </div>
        </TabsContent>
      ))}
    </Tabs>
  )
}

Desabilitado

Abas desabilitadas são ignoradas pelo teclado.

import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"

export function TabsDisabled() {
  return (
    <Tabs defaultValue="day">
      <TabsList>
        <TabsTrigger value="day">Day</TabsTrigger>
        <TabsTrigger value="week">Week</TabsTrigger>
        <TabsTrigger value="month" disabled>
          Month
        </TabsTrigger>
      </TabsList>
    </Tabs>
  )
}

Controlado

Passe value e onValueChange. Mudanças de fora também deslizam o indicador.

"use client"

import * as React from "react"

import { Button } from "@/components/ui/button"
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"

const steps = ["Cart", "Shipping", "Payment", "Review"]

export function TabsControlled() {
  const [step, setStep] = React.useState("Cart")
  const index = steps.indexOf(step)

  return (
    <div className="flex flex-col items-start gap-4">
      <Tabs value={step} onValueChange={(value) => setStep(String(value))}>
        <TabsList>
          {steps.map((item) => (
            <TabsTrigger key={item} value={item}>
              {item}
            </TabsTrigger>
          ))}
        </TabsList>
      </Tabs>
      <Button
        size="sm"
        variant="outline"
        onClick={() => setStep(steps[(index + 1) % steps.length])}
      >
        Next step
      </Button>
    </div>
  )
}

Da direita para a esquerda

Abas, setas e o indicador seguem a direção de leitura.

import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"

export function TabsRtl() {
  return (
    <div dir="rtl" className="w-full max-w-sm">
      <Tabs defaultValue="account">
        <TabsList variant="line">
          <TabsTrigger value="account">الحساب</TabsTrigger>
          <TabsTrigger value="password">كلمة المرور</TabsTrigger>
          <TabsTrigger value="alerts">التنبيهات</TabsTrigger>
        </TabsList>
        <TabsContent value="account">
          <p className="py-2 text-sm text-muted-foreground">إعدادات الحساب.</p>
        </TabsContent>
        <TabsContent value="password">
          <p className="py-2 text-sm text-muted-foreground">
            غيّر كلمة المرور.
          </p>
        </TabsContent>
        <TabsContent value="alerts">
          <p className="py-2 text-sm text-muted-foreground">إدارة التنبيهات.</p>
        </TabsContent>
      </Tabs>
    </div>
  )
}
TeclaAção
TabEntra na lista na aba ativa e depois no painel.
←→Move entre as abas, voltando ao início nas extremidades. ↑ e ↓ na vertical.
HomeEndMove para a primeira ou a última aba.
EnterSpaceAbre a aba com foco. Defina activateOnFocus em TabsList para abrir as abas conforme o foco se move.
  • A lista é um tablist; cada gatilho é um tab que controla seu tabpanel.
  • Os painéis são focáveis, então usuários de teclado alcançam conteúdo que não tem links nem botões.
  • Com movimento reduzido, o indicador salta em vez de deslizar.
PropTipoPadrão
value
any–
defaultValue
any0
onValueChange
(value, details) => void–
orientation
"horizontal" | "vertical""horizontal"
AtributoDescrição
data-activation-direction"left", "right", "up" ou "down": onde a nova aba está em relação à antiga.
PropTipoPadrão
variant
"default" | "line""default"
activateOnFocus
booleanfalse
loopFocus
booleantrue
AtributoDescrição
data-slot="tabs-indicator"A pílula ou o sublinhado deslizante.
data-scrolled-start / data-scrolled-endPresente quando a lista pode rolar nessa direção.
--active-tab-left / --active-tab-widthPosição e tamanho da aba ativa, também -top e -height.
PropTipoPadrão
value
any–
disabled
booleanfalse
render
ReactElement | (props, state) => ReactElement<button>
AtributoDescrição
data-activeA aba aberta.
data-disabledA aba está desabilitada.
PropTipoPadrão
value
any–
keepMountedMantém o painel no DOM enquanto oculto.
booleanfalse

Usado em blocos

Blocos que se baseiam em Tabs.