Вкладки
Компонент переключения вкладок с контролируемым / неконтролируемым режимами, карточным / линейным внешним видом, закрытием и добавлением вкладок, а также полной поддержкой клавиатуры.
Базовое использование
import { useState } from 'react'
import { LhTabs, LhTabPane } from '@lh-ui/react'
export default function Demo() {
const [value, setValue] = useState('ink')
return (
<LhTabs value={value} onChange={(name) => setValue(name)}>
<LhTabPane name="ink" label="Тушь">
Размытая тушь, живая и плавная.
</LhTabPane>
<LhTabPane name="danqing" label="Даньцин">
Раскраска даньцин, золотое и изумрудное сияние.
</LhTabPane>
</LhTabs>
)
}
Tabs Props
| Свойство | Описание | Тип | Варианты | По умолчанию |
|---|---|---|---|---|
| value | Имя активной вкладки (контролируемое) | string | — | — |
| defaultValue | Имя активной вкладки (по умолчанию, неконтролируемое) | string | — | — |
| type | Внешний вид | 'line' | 'card' | — | 'line' |
| closable | Можно ли закрывать вкладки | boolean | — | false |
| addable | Показывать ли кнопку добавления | boolean | — | false |
| tabPosition | Положение вкладок | 'top' | 'bottom' | — | 'top' |
| sx | Сокращённые props макета | SxProps | — | — |
TabPane Props
| Свойство | Описание | Тип | По умолчанию |
|---|---|---|---|
| name | Уникальный идентификатор вкладки (используется как стабильный ключ; динамически менять не рекомендуется) | string | — |
| label | Заголовок вкладки | ReactNode | — |
| disabled | Отключить | boolean | false |
| children | Содержимое вкладки | ReactNode | — |
События Tabs
| Событие | Описание | Сигнатура коллбэка | Аналог в Vue |
|---|---|---|---|
| onChange | Срабатывает при смене активной вкладки | (name: string) => void | @change |
| onRemove | Срабатывает при закрытии вкладки (видимость вкладки остаётся на усмотрение бизнес-логики) | (name: string) => void | @remove |
| onAdd | Срабатывает по клику на кнопку добавления | () => void | @add |
Передача value делает компонент контролируемым; передача defaultValue включает внутреннее неконтролируемое состояние. onChange срабатывает в обоих режимах. При удалении активной вкладки неконтролируемый режим автоматически переключается на соседнюю доступную вкладку (поведение getNameAfterRemove из plus); в контролируемом режиме это остаётся за бизнес-логикой в onRemove.
children должны быть непосредственно элементами LhTabPane (можно выводить их через .map, допускается плоская обёртка во Fragment, но оборачивать в пользовательский компонент нельзя) — родитель собирает записи вкладок, спускаясь через Children.forEach, и пользовательская обёртка ломает сбор.
Взаимодействие с клавиатурой
Следует шаблону вкладок из APG (tabs pattern): когда фокус находится на кнопке вкладки, ArrowRight / ArrowLeft (либо ArrowDown / ArrowUp в вертикальном режиме) перемещают между доступными вкладками и активируют их, пропуская отключённые; Home / End перемещают к первой / последней вкладке; Delete / Backspace закрывают текущую вкладку (требуется closable). Только активная вкладка имеет tabindex=0, остальные — -1 (roving tabindex).
Доступность
Лента вкладок имеет role="tablist", вкладки — role="tab" с aria-selected / aria-controls, а панели — role="tabpanel" с aria-labelledby; id генерируются через useId() и стабильны при SSR. Неактивные панели удаляются из дерева доступности атрибутом hidden.
ref
forwardRef<HTMLDivElement> — корневой элемент. LhTabPane прокидывает HTMLDivElement.
Стили
import '@lh-ui/react/theme.css'
import '@lh-ui/react/style/tabs'