Динамические табы — это элементы интерфейса, которые позволяют пользователю переключаться между различными панелями контента, при этом их количество и структура могут изменяться во время работы приложения. В библиотеке React Aria реализована мощная система управления табами, которая обеспечивает корректную работу с доступностью, фокусом и управлением состоянием.
В React Aria состояние табов отделено от их визуального отображения. Для динамических табов ключевым является useTabListState. Этот хук принимает объект с параметрами и возвращает состояние таб-листа:
import { useTabListState } from "@react-stately/tabs";
const state = useTabListState({
selectedKey: "tab1",
defaultSelectedKey: "tab1",
items: [
{ key: "tab1", name: "Первый" },
{ key: "tab2", name: "Второй" }
]
});
selectedKey — текущий активный таб.defaultSelectedKey — таб, который будет активен при
первой отрисовке.items — массив объектов, представляющих табы, каждый
объект должен иметь уникальный ключ key и отображаемое имя
name.Для динамических табов массив items может меняться во
время выполнения, что позволит добавлять и удалять вкладки.
Компонент TabList управляет фокусом и взаимодействием с
клавиатурой. React Aria предоставляет хук
useTabList:
import { useTabList } from "@react-aria/tabs";
import { useRef } from "react";
function TabListComponent({ state }) {
const ref = useRef();
const { tabListProps } = useTabList({ orientation: "horizontal" }, state, ref);
return (
<div {...tabListProps} ref={ref}>
{state.collection.map(item => (
<Tab key={item.key} item={item} state={state} />
))}
</div>
);
}
orientation задаёт направление табов:
horizontal или vertical.tabListProps содержит свойства для корректной работы с
клавиатурой и фокусом.state.collection автоматически обновляется при
изменении списка табов.Каждая вкладка рендерится через компонент Tab с
использованием хука useTab:
import { useTab } from "@react-aria/tabs";
function Tab({ item, state }) {
const ref = useRef();
const { tabProps } = useTab({ key: item.key }, state, ref);
return (
<button {...tabProps} ref={ref}>
{item.name}
</button>
);
}
tabProps включает обработку событий клавиатуры, роль
tab и атрибуты aria-selected.ref используется для управления фокусом при навигации с
клавиатуры.React Aria автоматически обеспечивает правильную работу клавиш
ArrowLeft, ArrowRight, Home и
End, перемещая фокус между вкладками.
Для отображения содержимого вкладок используется компонент
TabPanel с хуком useTabPanel:
import { useTabPanel } from "@react-aria/tabs";
function TabPanel({ children, item, state }) {
const ref = useRef();
const { tabPanelProps } = useTabPanel({ key: item.key }, state, ref);
return (
<div {...tabPanelProps} ref={ref}>
{children}
</div>
);
}
tabPanelProps задаёт атрибуты
role="tabpanel" и aria-labelledby, связывая
панель с соответствующим табом.hidden
и поддерживает доступность для скринридеров.Для динамических интерфейсов список табов можно изменять через состояние React:
const [tabs, setTabs] = useState([
{ key: "tab1", name: "Первый" },
{ key: "tab2", name: "Второй" }
]);
const addTab = () => {
const newKey = `tab${tabs.length + 1}`;
setTabs([...tabs, { key: newKey, name: `Вкладка ${tabs.length + 1}` }]);
};
const removeTab = key => {
setTabs(tabs.filter(tab => tab.key !== key));
};
После обновления tabs объект состояния
useTabListState автоматически обновит коллекцию и
отобразит новые табы.
React Aria гарантирует корректные ARIA-атрибуты:
role="tablist" для контейнера.role="tab" для каждой вкладки.aria-selected="true/false" у активного/неактивного
таба.aria-controls связывает таб с панелью.role="tabpanel" у панели контента, связанной с табом
через aria-labelledby.Для динамических табов важно сохранять уникальные ключи
key, чтобы состояние фокуса и активной вкладки корректно
обновлялось при изменении списка.
React Aria поддерживает обе ориентации:
orientation: "horizontal") —
стандартная раскладка табов сверху.orientation: "vertical") — вкладки
располагаются слева или справа.Компоненты автоматически адаптируют клавиши навигации под ориентацию
(ArrowUp/ArrowDown для вертикальной ориентации).
Библиотека обеспечивает управление фокусом, даже если табы добавляются динамически:
Home и End для быстрого
перехода к первой и последней вкладке.React Aria не накладывает ограничения на визуальные эффекты:
border-bottom или background-color, связывая
их с состоянием state.selectedKey.Полный динамический таб-лист выглядит следующим образом:
function DynamicTabs() {
const [tabs, setTabs] = useState([{ key: "tab1", name: "Первый" }]);
const state = useTabListState({ items: tabs });
return (
<div>
<TabListComponent state={state} />
{tabs.map(tab => (
<TabPanel key={tab.key} item={tab} state={state}>
Контент {tab.name}
</TabPanel>
))}
<button onCl ick={() => addTab()}>Добавить вкладку</button>
</div>
);
}
Такой подход обеспечивает: