# Code Block

> Tabbed package-manager code block with npm/pnpm/yarn/bun switcher, syntax-highlighted command output, and a one-click copy button.

A shadcn/ui block from the [@uiception](https://uiception.com) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/uiception/code-block).

- Page, with a live preview: https://shadcn.exchange/r/uiception/code-block
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/uiception/code-block-light-bb2adba10cec183b.png
- Registry item: https://uiception.com/r/code-block.json
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://uiception.com/r/code-block.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Files

### `registry/new-york/blocks/code-block/page.tsx`

```tsx
import CodeBlock from "./components/code-block"

export default function Page() {
  return (
    <div className="px-4 py-10 md:px-6 md:py-14">
      <CodeBlock />
    </div>
  )
}
```

### `registry/new-york/blocks/code-block/components/code-block.tsx`

```tsx
"use client"

import { cn } from "@/lib/utils"

import CodeTabs from "./code-tabs"
import { useCodeBlock } from "../hooks/use-code-block"
import "../styles/code-block.css"

export default function CodeBlock({ className }: { className?: string }) {
  const { activeTab, setActiveTab, copied, handleCopy } = useCodeBlock()

  return (
    <div
      className={cn(
        "mx-auto flex w-full max-w-3xl min-w-0 justify-center px-3.5 py-[18px]",
        className
      )}
    >
      <div className="w-full max-w-[680px]">
        <CodeTabs
          activeTab={activeTab}
          copied={copied}
          onTabChange={setActiveTab}
          onCopy={handleCopy}
        />
      </div>
    </div>
  )
}
```

### `registry/new-york/blocks/code-block/components/code-tabs.tsx`

```tsx
"use client"

import * as React from "react"
import { Check, Copy } from "lucide-react"
import { cn } from "@/lib/utils"
import { TAB_OPTIONS, COMMANDS, type TabOption } from "../lib/config"

import "../styles/code-block.css"

type Props = {
  activeTab: TabOption
  copied: boolean
  onTabChange: (tab: TabOption) => void
  onCopy: () => void
}

export default function CodeTabs({
  activeTab,
  copied,
  onTabChange,
  onCopy,
}: Props) {
  const tabRefs = React.useRef<(HTMLButtonElement | null)[]>([])
  const [indicator, setIndicator] = React.useState({ left: 0, width: 0 })

  React.useLayoutEffect(() => {
    const idx = TAB_OPTIONS.indexOf(activeTab)
    const el = tabRefs.current[idx]
    if (el) setIndicator({ left: el.offsetLeft, width: el.offsetWidth })
  }, [activeTab])

  const cmd = COMMANDS[activeTab]
  const [pkgManager, action, ...pkgs] = cmd.split(" ")

  return (
    <div className="overflow-hidden rounded-lg border border-[#eaeaea] bg-white dark:border-[#1a1a1a] dark:bg-black">
      <div className="relative flex items-center gap-3 border-b border-[#eaeaea] px-4 dark:border-[#1a1a1a]">
        {TAB_OPTIONS.map((tab, i) => (
          <button
            key={tab}
            ref={(el) => {
              tabRefs.current[i] = el
            }}
            onClick={() => onTabChange(tab)}
            className={cn(
              "cursor-pointer border-none bg-transparent py-2 text-sm font-medium text-[#a0a0a0] transition-colors duration-150 hover:text-[#171717] dark:hover:text-[#eeeeee]",
              activeTab === tab && "text-[#171717] dark:text-[#eeeeee]"
            )}
          >
            {tab}
          </button>
        ))}
        <div
          className="pointer-events-none absolute bottom-0 h-px bg-[#9a7b2d] transition-[left,width] duration-200 ease-out motion-reduce:transition-none dark:bg-[#cca649]"
          style={{ left: indicator.left, width: indicator.width }}
        />
        <div
          className="pointer-events-none absolute bottom-0 h-2 bg-[color-mix(in_srgb,#9a7b2d_25%,transparent)] blur-[3px] transition-[left,width] duration-200 ease-out motion-reduce:transition-none dark:bg-[color-mix(in_srgb,#cca649_25%,transparent)]"
          style={{ left: indicator.left, width: indicator.width }}
        />
      </div>

      <div className="flex items-center justify-between gap-4 overflow-x-auto bg-[#f5f5f5] px-4 py-2.5 font-mono text-sm dark:bg-[#1a1a1a]">
        <code
          key={activeTab}
          className="cblk-cmd inline-flex text-left whitespace-nowrap"
        >
          <span className="text-[#0070f3] dark:text-[#47a8ff]">
            {pkgManager}
          </span>
          <span className="ml-2 text-[#d6336c] dark:text-[#ff4d8d]">
            {action}
          </span>
          <span className="ml-2 text-[#067a3d] dark:text-[#00c45c]">
            {pkgs.join(" ")}
          </span>
        </code>

        <button
          onClick={onCopy}
          className={cn(
            "shrink-0 cursor-pointer rounded border-none bg-transparent p-1 text-[#6b7280] transition-colors duration-150 hover:bg-[#f0f0f0] hover:text-[#171717] dark:hover:bg-[#2a2a2a] dark:hover:text-[#eeeeee]",
            copied && "text-[#067a3d] dark:text-[#00c45c]"
          )}
          title="Copy command"
        >
          {copied ? <Check size={14} /> : <Copy size={14} />}
        </button>
      </div>
    </div>
  )
}
```

### `registry/new-york/blocks/code-block/hooks/use-code-block.ts`

```ts
import { useState } from "react"
import { COMMANDS, type TabOption } from "../lib/config"

export function useCodeBlock() {
  const [activeTab, setActiveTab] = useState<TabOption>("npm")
  const [copied, setCopied] = useState(false)

  const handleCopy = async () => {
    await navigator.clipboard.writeText(COMMANDS[activeTab])
    setCopied(true)
    setTimeout(() => setCopied(false), 2000)
  }

  return { activeTab, setActiveTab, copied, handleCopy }
}
```

### `registry/new-york/blocks/code-block/lib/config.ts`

```ts
// Example: Fumadocs installation commands
export const TAB_OPTIONS = ["npm", "pnpm", "yarn", "bun"] as const
export type TabOption = (typeof TAB_OPTIONS)[number]

export const COMMANDS: Record<TabOption, string> = {
  npm: "npm i fumadocs-mdx fumadocs-core @types/mdx",
  pnpm: "pnpm add fumadocs-mdx fumadocs-core @types/mdx",
  yarn: "yarn add fumadocs-mdx fumadocs-core @types/mdx",
  bun: "bun add fumadocs-mdx fumadocs-core @types/mdx",
}
```

### `registry/new-york/blocks/code-block/styles/code-block.css`

```css
/* code-block — tab switch fade-in */

@keyframes cb-fade-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

.cblk-cmd {
  animation: cb-fade-in 0.15s ease-out forwards;
}

@media (prefers-reduced-motion: reduce) {
  .cblk-cmd {
    animation: none;
  }
}
```
