A component for toggling between related panels on the same page. The Tabs component extends Base UI's Tabs. It adds an animated Tabs.Indicator, horizontal and vertical orientations, and a segmented variant on Tabs.List.
Here is the component implementation code that you can copy to your project:
// https://devie-ui.com/components/tabs
// https://base-ui.com/react/components/tabs
import { Tabs as BaseTabs } from "@base-ui/react/tabs";
import clsx from "clsx";
import styles from "./Tabs.module.scss";
const Root = BaseTabs.Root;
function List({ className, variant = "underline", ...props }: Tabs.List.Props) {
return (
<BaseTabs.List
className={clsx(
styles.list,
variant === "segmented" && styles.listSegmented,
className,
)}
{...props}
/>
);
}
const tabStyles = styles.tab;
function Tab({ className, ...props }: BaseTabs.Tab.Props) {
return <BaseTabs.Tab className={clsx(tabStyles, className)} {...props} />;
}
function Indicator({ className, ...props }: BaseTabs.Indicator.Props) {
return (
<BaseTabs.Indicator
className={clsx(styles.indicator, className)}
{...props}
/>
);
}
function Panel({ className, ...props }: BaseTabs.Panel.Props) {
return (
<BaseTabs.Panel className={clsx(styles.panel, className)} {...props} />
);
}
const Tabs = {
Root,
List,
Tab,
Indicator,
Panel,
};
namespace Tabs {
export namespace Root {
export type Props = BaseTabs.Root.Props;
export type ChangeEventDetails = BaseTabs.Root.ChangeEventDetails;
}
export namespace List {
export type Variant = "underline" | "segmented";
export interface Props extends BaseTabs.List.Props {
variant?: Variant;
}
}
export namespace Tab {
export type Props = BaseTabs.Tab.Props;
export type State = BaseTabs.Tab.State;
}
export namespace Indicator {
export type Props = BaseTabs.Indicator.Props;
}
export namespace Panel {
export type Props = BaseTabs.Panel.Props;
}
}
export default Tabs;Horizontal tabs with an animated underline indicator. Use defaultValue to set the initially selected tab, or use value and onValueChange for controlled mode.
Set the orientation prop on the Root to "vertical" for a vertical tab layout. The indicator automatically displays as a vertical line on the right.
Set variant to segmented on Tabs.List. The indicator becomes a raised pill inside a sunken track. Works with both orientations.
Override the indicator styles via className to create custom designs like a filled background with border and radius.