Tabs
trovecn/tabsFreeComponent
Tab list with a spring-driven sliding indicator, proximity hover, and a directional panel handoff.
Install it
npx shadcn@latest add https://trovecn.dev/r/tabs.jsonSource
1"use client";23import {4 Children,5 cloneElement,6 createContext,7 isValidElement,8 useCallback,9 useContext,10 useEffect,11 useLayoutEffect,12 useRef,13 useState,14 type ReactElement,15} from "react";16import { Tabs as TabsPrimitive } from "@base-ui/react/tabs";17import { motion, AnimatePresence, useReducedMotion } from "motion/react";1819import { cn } from "@/lib/utils";20import { spring } from "@/lib/springs";21import { fontWeights } from "@/lib/font-weight";22import {23 useProximityHover,24 proximityHoverWashClassName,25 proximityHoverWashOpacity,26 type ItemRect,27} from "@/hooks/use-proximity-hover";2829// ─── Contexts ────────────────────────────────────────────────────────────────30// Base UI doesn't expose a public hook for "which value is active" to31// arbitrary descendants (only its own Root/List/Tab/Panel/Indicator32// components can see that internally) — TabsList needs it to resolve the33// selected tab's index into `itemRects`, so Tabs tracks it itself instead.3435interface TabsValueOrderContextValue {36 valueOrder: string[];37 setValueOrder: (order: string[]) => void;38 selectedValue: string | undefined;39}4041const TabsValueOrderContext = createContext<TabsValueOrderContextValue | null>(null);4243interface TabsListContextValue {44 registerTab: (index: number, element: HTMLElement | null) => void;45 hoveredIndex: number | null;46 selectedValue: string | undefined;47 /** Optimistically set on click so the indicator jumps immediately, without waiting for the controlled value to round-trip back. */48 setOptimisticIndex: (index: number) => void;49}5051const TabsListContext = createContext<TabsListContextValue | null>(null);5253function useTabsListContext() {54 const ctx = useContext(TabsListContext);55 if (!ctx) throw new Error("TabsTrigger must be used within a TabsList");56 return ctx;57}5859// ─── Tabs ────────────────────────────────────────────────────────────────────6061function Tabs({62 value,63 onValueChange,64 defaultValue,65 children,66 className,67 ...props68}: TabsPrimitive.Root.Props) {69 const [valueOrder, setValueOrder] = useState<string[]>([]);70 const [uncontrolledValue, setUncontrolledValue] = useState<unknown>(defaultValue);7172// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from trovecn
All 26 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordionaccordion | trovecn | Components | Free | 3 deps | |
| Agent Activityagent-activity | trovecn | Components | Free | 2 deps | |
| Approval Requestapproval-request | trovecn | Components | Free | 2 deps | |
| Buttonbutton | trovecn | Components | Free | 2 deps | |
| Checkboxcheckbox | trovecn | Components | Free | 2 deps | |
| Checkbox Groupcheckbox-group | trovecn | Components | Free | 2 deps | |
| Comboboxcombobox | trovecn | Components | Free | 3 deps | |
| Comparison Slidercomparison-slider | trovecn | Components | Free | 1 dep |
