AI Overview
Understand the current landscape of artificial intelligence, trends, and applications across industries.
1'use client';23import { Button } from '@/components/ui/button';4import { Card } from '@/components/ui/card';5import { Tabs } from '@/components/ui/tabs';67export function Default() {8 return (9 <Tabs defaultValue="overview" variant="default" size="sm">10 <Tabs.List>11 <Tabs.Trigger value="overview">Overview</Tabs.Trigger>12 <Tabs.Trigger value="models">Models</Tabs.Trigger>13 <Tabs.Trigger value="research">Research</Tabs.Trigger>14 <Tabs.Trigger value="ethics">Ethics</Tabs.Trigger>15 </Tabs.List>1617 <Tabs.Content value="overview">18 <Card className="border-border shadow-sm">19 <Card.Header>20 <Card.Title>AI Overview</Card.Title>21 <Card.Description>22 Understand the current landscape of artificial intelligence, trends, and applications23 across industries.24 </Card.Description>25 </Card.Header>26 <Card.Content className="flex flex-col gap-3">27 <div className="flex gap-3">28 <Button onClick={() => alert('Viewing AI trends')} variant="secondary">29 View Trends30 </Button>31 <Button variant="ghost" onClick={() => alert('Explore applications')}>32 Explore Applications33 </Button>34 </div>35 </Card.Content>36 </Card>37 </Tabs.Content>3839 <Tabs.Content value="models">40 <Card className="border-border shadow-sm">41 <Card.Header>42 <Card.Title>AI Models</Card.Title>43 <Card.Description>44 Track the performance of different AI models, from NLP and computer vision to45 reinforcement learning systems.46 </Card.Description>47 </Card.Header>48 <Card.Content>49 <Button onClick={() => alert('Opening model library')} variant="secondary">50 View Models51 </Button>52 </Card.Content>53 </Card>54 </Tabs.Content>5556 <Tabs.Content value="research">57 <Card className="border-border shadow-sm">58 <Card.Header>59 <Card.Title>Research & Publications</Card.Title>60 <Card.Description>61 Stay up-to-date with the latest research papers, case studies, and breakthroughs in AI62 technology.63 </Card.Description>64 </Card.Header>65 <Card.Content>66 <Button onClick={() => alert('Browsing research papers')} variant="secondary">67 Browse Research68 </Button>69 </Card.Content>70 </Card>71 </Tabs.Content>7273 <Tabs.Content value="ethics">74 <Card className="border-border shadow-sm">75 <Card.Header>76 <Card.Title>Ethics & Governance</Card.Title>77 <Card.Description>78 Understand ethical considerations, regulations, and best practices for responsible AI79 deployment.80 </Card.Description>81 </Card.Header>82 <Card.Content className="flex gap-3">83 <Button onClick={() => alert('View guidelines')} variant="secondary">84 View Guidelines85 </Button>86 <Button variant="ghost" onClick={() => alert('Report concerns')}>87 Report Concerns88 </Button>89 </Card.Content>90 </Card>91 </Tabs.Content>92 </Tabs>93 );94}
Installation
Copy and paste the following code in your project.
'use client';import { cva, type VariantProps } from 'class-variance-authority';import { motion } from 'motion/react';import * as React from 'react';import { cn } from '../lib/cn';// --- Animation constants (module level) ---const TABS_INDICATOR_TRANSITION = { type: 'spring', bounce: 0.2, duration: 0.6 } as const;// --- CVA ---const tabsListVariants = cva('inline-flex rounded-md p-1 text-muted-foreground w-full sm:w-auto overflow-hidden',{variants: {variant: {default: 'bg-muted/50 border border-border/50 backdrop-blur-sm',outline: 'border border-border bg-transparent',underline: 'bg-transparent border-b border-border rounded-none p-0 justify-start w-full',ghost: 'bg-transparent p-0 gap-2',},size: {default: 'h-10',sm: 'h-9',lg: 'h-12',},},},);const tabsTriggerVariants = cva('relative inline-flex items-center justify-center whitespace-nowrap px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 z-10 cursor-pointer',{variants: {variant: {default: 'text-muted-foreground data-[state=active]:text-foreground',outline: 'text-muted-foreground data-[state=active]:text-foreground',underline:'text-muted-foreground hover:text-foreground data-[state=active]:text-foreground rounded-none bg-transparent px-4 pb-3 pt-2',ghost:'text-muted-foreground hover:text-foreground data-[state=active]:text-foreground hover:bg-muted/50 rounded-md',},size: {default: 'text-sm',sm: 'text-xs',lg: 'text-base px-5',},},defaultVariants: {variant: 'default',size: 'default',},},);// --- Context ---interface TabsContextValue {activeTab: string;setActiveTab: (value: string) => void;direction: number;setDirection: (dir: number) => void;variant: NonNullable<TabsProps['variant']>;layoutId: string;}const TabsContext = React.createContext<TabsContextValue | null>(null);function useTabsContext() {const context = React.use(TabsContext);if (!context) throw new Error('Tabs components must be used within Tabs');return context;}// --- Components ---interface TabsProps extends React.HTMLAttributes<HTMLDivElement> {defaultValue?: string;value?: string;onValueChange?: (value: string) => void;variant?: 'default' | 'outline' | 'underline' | 'ghost';size?: 'default' | 'sm' | 'lg';}const TabsRoot = ({className,defaultValue,value: controlledValue,onValueChange,variant = 'default',size = 'default',children,ref,...props}: TabsProps & { ref?: React.Ref<HTMLDivElement> }) => {const [internalValue, setInternalValue] = React.useState(defaultValue || '');const isControlled = controlledValue !== undefined;const activeTab = isControlled ? controlledValue : internalValue;const [direction, setDirection] = React.useState(0);const layoutId = React.useId();const setActiveTab = React.useCallback((newValue: string) => {if (!isControlled) {setInternalValue(newValue);}onValueChange?.(newValue);},[isControlled, onValueChange],);return (<TabsContextvalue={{activeTab,setActiveTab,direction,setDirection,variant,layoutId,}}><div ref={ref} className={cn('w-full', className)} {...props}>{children}</div></TabsContext>);};TabsRoot.displayName = 'Tabs';interface TabsListPropsextends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof tabsListVariants> {}const TabsList = ({className,variant,size,children,ref,...props}: TabsListProps & { ref?: React.Ref<HTMLDivElement> }) => {const { variant: contextVariant } = useTabsContext();const finalVariant = variant || contextVariant;return (<divref={ref}role="tablist"aria-orientation="horizontal"className={cn(tabsListVariants({ variant: finalVariant, size }), className)}{...props}>{children}</div>);};TabsList.displayName = 'TabsList';interface TabsTriggerPropsextends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof tabsTriggerVariants> {value: string;children: React.ReactNode;}const TabsTrigger = ({className,value,children,variant,size,ref,...props}: TabsTriggerProps & { ref?: React.Ref<HTMLButtonElement> }) => {const {activeTab,setActiveTab,setDirection,variant: contextVariant,layoutId,} = useTabsContext();const isActive = activeTab === value;const finalVariant = variant || contextVariant;const buttonRef = React.useRef<HTMLButtonElement>(null);const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {const parent = buttonRef.current?.parentElement;if (parent) {const childrenArray = Array.from(parent.children);const newIndex = childrenArray.indexOf(buttonRef.current!);const currentIndex = childrenArray.findIndex((child) => child.getAttribute('data-state') === 'active',);if (currentIndex !== -1 && newIndex !== currentIndex) {setDirection(newIndex > currentIndex ? 1 : -1);}}setActiveTab(value);props.onClick?.(e);};// Merge the external ref with our internal buttonRefReact.useEffect(() => {if (!ref) return;if (typeof ref === 'function') {ref(buttonRef.current);} else {(ref as any).current = buttonRef.current;}}, [ref]);return (<buttonref={buttonRef}type="button"role="tab"id={`${layoutId}-trigger-${value}`}aria-selected={isActive}aria-controls={`${layoutId}-content-${value}`}tabIndex={isActive ? 0 : -1}data-state={isActive ? 'active' : 'inactive'}onClick={handleClick}className={cn(tabsTriggerVariants({ variant: finalVariant, size }), className)}{...props}><span className="inherit relative z-20">{children}</span>{isActive && (<motion.divlayoutId={`${layoutId}-indicator`}className={cn('absolute inset-0 z-10',finalVariant === 'underline'? 'bg-primary top-auto bottom-0 h-[2px] shadow-[0_0_10px_rgba(var(--primary),0.5)]': 'bg-secondary border-border/50 rounded-sm border shadow-sm',)}transition={TABS_INDICATOR_TRANSITION}/>)}</button>);};TabsTrigger.displayName = 'TabsTrigger';interface TabsContentProps extends React.HTMLAttributes<HTMLDivElement> {value: string;}const TabsContent = ({className,value,children,ref,...props}: TabsContentProps & { ref?: React.Ref<HTMLDivElement> }) => {const { activeTab, layoutId } = useTabsContext();const isActive = activeTab === value;if (!isActive) return null;return (<divref={ref}role="tabpanel"id={`${layoutId}-content-${value}`}aria-labelledby={`${layoutId}-trigger-${value}`}tabIndex={0}className={cn('ring-offset-background focus-visible:ring-ring mt-4 focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none',className,)}{...props}>{children}</div>);};TabsContent.displayName = 'TabsContent';const Tabs = Object.assign(TabsRoot, {List: TabsList,Trigger: TabsTrigger,Content: TabsContent,});export { Tabs };
Make sure to update the import paths according to your project structure.
Anatomy
import { Tabs } from '@/components/ui/tabs';
<Tabs defaultValue="account"><Tabs.List><Tabs.Trigger value="account">Account</Tabs.Trigger><Tabs.Trigger value="password">Password</Tabs.Trigger></Tabs.List><Tabs.Content value="account">Account settings content</Tabs.Content><Tabs.Content value="password">Password settings content</Tabs.Content></Tabs>
Features
- Multiple variants - Default, outline, underline, and ghost styles
- Animated indicator - Smooth sliding active tab indicator
- Keyboard navigation - Full keyboard support
- Smooth transitions - Animated content switching
API Reference
Tabs
Root component that manages tab state.
| Prop | Type | Default | Description |
|---|---|---|---|
defaultValue | string | - | Default active tab |
value | string | - | Controlled active tab |
onValueChange | (value: string) => void | - | Callback when tab changes |
variant | 'default' | 'outline' | 'underline' | 'ghost' | 'default' | Visual style |
size | 'default' | 'sm' | 'lg' | 'default' | Tab size |
className | string | - | Additional CSS classes |
TabsList
Container for tab triggers.
| Prop | Type | Default | Description |
|---|---|---|---|
variant | 'default' | 'outline' | 'underline' | 'ghost' | Inherits | Override variant |
size | 'default' | 'sm' | 'lg' | Inherits | Override size |
className | string | - | Additional CSS classes |
TabsTrigger
Individual tab button.
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | - | Unique tab identifier |
variant | 'default' | 'outline' | 'underline' | 'ghost' | Inherits | Override variant |
size | 'default' | 'sm' | 'lg' | Inherits | Override size |
className | string | - | Additional CSS classes |
TabsContent
Content panel for each tab.
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | - | Matching tab identifier |
className | string | - | Additional CSS classes |
Variants
Default
Tabs with a subtle background and border.
Outline
Tabs with a border outline style.
Underline
Tabs with an underline indicator for the active tab.
Ghost
Minimal tabs with no background, just hover effects.