Code (5)
Shadcn.io is not affiliated with official shadcn/ui
Snippet Tabbed code display with one-click clipboard functionality and customizable content. Perfect for React documentation requiring code examples with Next.js integration and TypeScript support.
'use client'; import { Snippet, SnippetCopyButton, SnippetHeader, SnippetTabsContent, SnippetTabsList, SnippetTabsTrigger, } from '@/components/ui/shadcn-io/snippet'; import { BoxIcon, HeartIcon } from 'lucide-react'; import { useState } from 'react'; const commands = [ { label: 'kibo-ui', icon: HeartIcon, code: 'npx kibo-ui@latest add snippet', }, { label: 'shadcn', icon: BoxIcon, code: 'npx shadcn@latest add https://www.kibo-ui.com/registry/snippet.json', }, ]; const Example = () => { const [value, setValue] = useState(commands[0].label); const activeCommand = commands.find((command) => command.label === value); return ( <Snippet onValueChange={setValue} value={value}> <SnippetHeader> <SnippetTabsList> {commands.map((command) => ( <SnippetTabsTrigger key={command.label} value={command.label}> <command.icon size={14} /> <span>{command.label}</span> </SnippetTabsTrigger> ))} </SnippetTabsList> {activeCommand && ( <SnippetCopyButton onCopy={() => console.log(`Copied "${activeCommand.code}" to clipboard`) } onError={() => console.error( `Failed to copy "${activeCommand.code}" to clipboard` ) } value={activeCommand.code} /> )} </SnippetHeader> {commands.map((command) => ( <SnippetTabsContent key={command.label} value={command.label}> {command.code} </SnippetTabsContent> ))} </Snippet> ); }; export default Example; 'use client'; import { CheckIcon, CopyIcon } from 'lucide-react'; import { type ComponentProps, cloneElement, type HTMLAttributes, type ReactElement, useState, } from 'react'; import { Button } from '@/components/ui/button'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { cn } from '@/lib/utils'; export type SnippetProps = ComponentProps<typeof Tabs>; export const Snippet = ({ className, ...props }: SnippetProps) => ( <Tabs className={cn( 'group w-full gap-0 overflow-hidden rounded-md border', className )} {...(props as any)} /> ); export type SnippetHeaderProps = HTMLAttributes<HTMLDivElement>; export const SnippetHeader = ({ className, ...props }: SnippetHeaderProps) => ( <div className={cn( 'flex flex-row items-center justify-between border-b bg-secondary p-1', className )} {...(props as any)} /> ); export type SnippetCopyButtonProps = ComponentProps<typeof Button> & { value: string; onCopy?: () => void; onError?: (error: Error) => void; timeout?: number; }; export const SnippetCopyButton = ({ asChild, value, onCopy, onError, timeout = 2000, children, ...props }: SnippetCopyButtonProps) => { const [isCopied, setIsCopied] = useState(false); const copyToClipboard = () => { if ( typeof window === 'undefined' || !navigator.clipboard.writeText || !value ) { return; } navigator.clipboard.writeText(value).then(() => { setIsCopied(true); onCopy?.(); setTimeout(() => setIsCopied(false), timeout); }, onError); }; if (asChild) { return cloneElement(children as ReactElement, { // @ts-expect-error - we know this is a button onClick: copyToClipboard, }); } const icon = isCopied ? <CheckIcon size={14} /> : <CopyIcon size={14} />; return ( <Button className="opacity-0 transition-opacity group-hover:opacity-100" onClick={copyToClipboard} size="icon" variant="ghost" {...(props as any)} > {children ?? icon} </Button> ); }; export type SnippetTabsListProps = ComponentProps<typeof TabsList>; export const SnippetTabsList = TabsList; export type SnippetTabsTriggerProps = ComponentProps<typeof TabsTrigger>; export const SnippetTabsTrigger = ({ className, ...props }: SnippetTabsTriggerProps) => ( <TabsTrigger className={cn('gap-1.5', className)} {...(props as any)} /> ); export type SnippetTabsContentProps = ComponentProps<typeof TabsContent>; export const SnippetTabsContent = ({ className, children, ...props }: SnippetTabsContentProps) => ( <TabsContent asChild className={cn('mt-0 bg-background p-4 text-sm', className)} {...(props as any)} > <pre className="truncate">{children}</pre> </TabsContent> );
npx shadcn@latest add https://www.shadcn.io/registry/snippet.jsonnpx shadcn@latest add https://www.shadcn.io/registry/snippet.jsonpnpm dlx shadcn@latest add https://www.shadcn.io/registry/snippet.jsonbunx shadcn@latest add https://www.shadcn.io/registry/snippet.jsonSign in to access installation commands Sign in
One-click clipboard functionality using native browser APIs with visual feedback and success indicators
Customizable tab system supporting unlimited tabs with flexible content and styling options
Multiple content support handling code snippets, command examples, and installation instructions
Accessible interface built on Radix UI Tabs primitive with full keyboard navigation and screen reader support
Flexible copy button with configurable timeout, custom callbacks, and success/error states
Custom tab triggers allowing personalized labels, icons, and interactive elements
Content customization supporting rich text, syntax highlighting, and formatted code blocks
TypeScript support with complete interface definitions for reliable integration
Responsive design adapting to mobile and desktop viewports with touch-friendly interactions
'use client'; import { Snippet, SnippetCopyButton, SnippetHeader, SnippetTabsContent, SnippetTabsList, SnippetTabsTrigger, } from '@/components/ui/shadcn-io/snippet'; import { useState } from 'react'; const commands = [ { label: 'npm', code: 'npx next-forge@latest init', }, { label: 'yarn', code: 'yarn dlx next-forge@latest init', }, { label: 'pnpm', code: 'pnpx next-forge@latest init', }, { label: 'bun', code: 'bunx next-forge@latest init', }, ]; const Example = () => { const [value, setValue] = useState(commands[0].label); const activeCommand = commands.find((command) => command.label === value); return ( <Snippet onValueChange={setValue} value={value}> <SnippetHeader> <SnippetTabsList> {commands.map((command) => ( <SnippetTabsTrigger key={command.label} value={command.label}> {command.label} </SnippetTabsTrigger> ))} </SnippetTabsList> {activeCommand && ( <SnippetCopyButton onCopy={() => console.log(`Copied "${activeCommand.code}" to clipboard`) } onError={() => console.error( `Failed to copy "${activeCommand.code}" to clipboard` ) } value={activeCommand.code} /> )} </SnippetHeader> {commands.map((command) => ( <SnippetTabsContent key={command.label} value={command.label}> {command.code} </SnippetTabsContent> ))} </Snippet> ); }; export default Example; 'use client'; import { CheckIcon, CopyIcon } from 'lucide-react'; import { type ComponentProps, cloneElement, type HTMLAttributes, type ReactElement, useState, } from 'react'; import { Button } from '@/components/ui/button'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { cn } from '@/lib/utils'; export type SnippetProps = ComponentProps<typeof Tabs>; export const Snippet = ({ className, ...props }: SnippetProps) => ( <Tabs className={cn( 'group w-full gap-0 overflow-hidden rounded-md border', className )} {...(props as any)} /> ); export type SnippetHeaderProps = HTMLAttributes<HTMLDivElement>; export const SnippetHeader = ({ className, ...props }: SnippetHeaderProps) => ( <div className={cn( 'flex flex-row items-center justify-between border-b bg-secondary p-1', className )} {...(props as any)} /> ); export type SnippetCopyButtonProps = ComponentProps<typeof Button> & { value: string; onCopy?: () => void; onError?: (error: Error) => void; timeout?: number; }; export const SnippetCopyButton = ({ asChild, value, onCopy, onError, timeout = 2000, children, ...props }: SnippetCopyButtonProps) => { const [isCopied, setIsCopied] = useState(false); const copyToClipboard = () => { if ( typeof window === 'undefined' || !navigator.clipboard.writeText || !value ) { return; } navigator.clipboard.writeText(value).then(() => { setIsCopied(true); onCopy?.(); setTimeout(() => setIsCopied(false), timeout); }, onError); }; if (asChild) { return cloneElement(children as ReactElement, { // @ts-expect-error - we know this is a button onClick: copyToClipboard, }); } const icon = isCopied ? <CheckIcon size={14} /> : <CopyIcon size={14} />; return ( <Button className="opacity-0 transition-opacity group-hover:opacity-100" onClick={copyToClipboard} size="icon" variant="ghost" {...(props as any)} > {children ?? icon} </Button> ); }; export type SnippetTabsListProps = ComponentProps<typeof TabsList>; export const SnippetTabsList = TabsList; export type SnippetTabsTriggerProps = ComponentProps<typeof TabsTrigger>; export const SnippetTabsTrigger = ({ className, ...props }: SnippetTabsTriggerProps) => ( <TabsTrigger className={cn('gap-1.5', className)} {...(props as any)} /> ); export type SnippetTabsContentProps = ComponentProps<typeof TabsContent>; export const SnippetTabsContent = ({ className, children, ...props }: SnippetTabsContentProps) => ( <TabsContent asChild className={cn('mt-0 bg-background p-4 text-sm', className)} {...(props as any)} > <pre className="truncate">{children}</pre> </TabsContent> );
This free open source React component works well for:
Installation guides - Package manager commands and setup instructions built with Next.js
API documentation - Code examples and request/response snippets using TypeScript
Tutorial content - Step-by-step code examples with multiple language support
Command references - CLI commands and terminal examples using shadcn/ui design
Configuration examples - Environment variables and config file snippets
Code samples - Reusable code blocks for documentation using Tailwind CSS styling
Prop Type Default Description childrenReactNodeundefinedSnippetTab components or content defaultValuestringundefinedDefault active tab value classNamestringundefinedAdditional CSS classes for the container onValueChangefunctionundefinedCallback when active tab changes
Prop Type Default Description valuestringundefinedUnique identifier for the tab labelstringundefinedDisplay label for the tab trigger childrenReactNodeundefinedContent to display in the tab panel copyTextstringundefinedText to copy when copy button is clicked showCopyButtonbooleantrueWhether to show the copy button copyTimeoutnumber2000Duration in ms to show copy success state onCopyfunctionundefinedCallback when copy button is clicked classNamestringundefinedAdditional CSS classes for tab content
Component built on Radix UI Tabs primitive ensuring accessibility and keyboard navigation
Copy functionality uses Clipboard API with fallback for older browsers
Tab system supports unlimited tabs with dynamic content and conditional rendering
Copy success feedback includes visual state changes and configurable timeout duration
Content supports both plain text and rich JSX elements for flexible display options
Responsive design adapts tab layout and copy button positioning across device sizes
Compatible with shadcn/ui design system and Tailwind CSS utility classes
Error handling includes clipboard permission checks and graceful fallbacks
Performance optimized with lazy loading and efficient re-rendering for large tab sets
TypeScript interfaces ensure type safety for tab configuration and callback functions