# Code Block Command

Display install commands with package manager switcher and copy button.

```tsx
"use client"

import { CodeBlockCommand } from "@/components/code-block-command"

export default function CodeBlockCommandDemo() {
  return (
    <div className="w-full max-w-sm">
      <CodeBlockCommand
        pnpm="pnpm dlx shadcn add button"
        yarn="yarn shadcn add button"
        npm="npx shadcn add button"
        bun="bunx --bun shadcn add button"
      />
    </div>
  )
}

```

## Features

* Switch between pnpm, yarn, npm, and bun with a single click.
* Optional `prompt` tab for displaying a natural language instruction for AI agents to install packages or components.
* Automatically saves the user’s preferred package manager for future visits.
* Copy commands instantly with smooth animations showing success or failure states.
* `convertNpmCommand` utility to auto-convert a standard npm command to all package managers.

## Installation

<CodeTabs>
  <TabsListInstallType />

  <TabsContent value="cli">
    ```bash
    npx shadcn@latest add @ncdai/code-block-command
    ```
  </TabsContent>

  <TabsContent value="manual">
    <Steps>
      <Step>Install the following dependencies</Step>

      ```bash
      npm install clsx tailwind-merge class-variance-authority lucide-react motion jotai radix-ui @base-ui/react
      ```

      <Step>Add a cn helper</Step>

      ```ts title="lib/utils.ts" 
      import type { ClassValue } from "clsx"
      import { clsx } from "clsx"
      import { twMerge } from "tailwind-merge"

      export const cn = (...inputs: ClassValue[]) => {
        return twMerge(clsx(inputs))
      }

      export function absoluteUrl(path: string) {
        return `${process.env.NEXT_PUBLIC_APP_URL}${path}`
      }

      ```

      <Step>Install the required components</Step>

      * [Copy Button](https://chanhdai.com/components/copy-button)

      <Step>Copy and paste the following code into your project</Step>

      ```tsx title="components/tabs.tsx" 
      "use client"

      import { Tabs as TabsPrimitive } from "@base-ui/react/tabs"

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

      function Tabs({ className, ...props }: TabsPrimitive.Root.Props) {
        return (
          <TabsPrimitive.Root
            data-slot="tabs"
            className={cn("flex flex-col gap-2", className)}
            {...props}
          />
        )
      }

      function TabsList({ className, ...props }: TabsPrimitive.List.Props) {
        return (
          <TabsPrimitive.List
            data-slot="tabs-list"
            className={cn(
              "relative z-0 flex h-8 w-fit items-center justify-center rounded-lg p-0.5",
              "bg-zinc-50 text-muted-foreground dark:bg-zinc-900",
              "inset-ring-1 inset-ring-border/64",
              className
            )}
            {...props}
          />
        )
      }

      function TabsIndicator({ className, ...props }: TabsPrimitive.Indicator.Props) {
        return (
          <TabsPrimitive.Indicator
            data-slot="tabs-indicator"
            className={cn(
              "absolute bottom-0 left-0 -z-1 h-(--active-tab-height) w-(--active-tab-width) translate-x-(--active-tab-left) -translate-y-(--active-tab-bottom) rounded-md bg-white transition-[width,translate] duration-200 ease-in-out dark:bg-muted",
              "inset-ring-1 inset-ring-foreground/10 dark:inset-ring-foreground/6",
              className
            )}
            {...props}
          />
        )
      }

      function TabsTrigger({ className, ...props }: TabsPrimitive.Tab.Props) {
        return (
          <TabsPrimitive.Tab
            data-slot="tabs-trigger"
            className={cn(
              "flex flex-1 shrink-0 items-center justify-center gap-2 rounded-md px-4 py-1 font-sans text-sm font-medium whitespace-nowrap transition-[color,background-color] outline-none hover:text-foreground focus-visible:inset-ring-1 focus-visible:inset-ring-ring disabled:pointer-events-none disabled:opacity-50 data-active:text-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
              className
            )}
            {...props}
          />
        )
      }

      function TabsContent({ className, ...props }: TabsPrimitive.Panel.Props) {
        return (
          <TabsPrimitive.Panel
            data-slot="tabs-content"
            className={cn("flex-1 outline-none", className)}
            {...props}
          />
        )
      }

      export { Tabs, TabsContent, TabsIndicator, TabsList, TabsTrigger }

      ```

      ````tsx title="components/code-block-command.tsx" 
      "use client"

      import { useMemo } from "react"
      import { ScrollArea } from "@base-ui/react/scroll-area"
      import { useAtom } from "jotai"
      import { atomWithStorage } from "jotai/utils"

      import { cn } from "@/lib/utils"
      import {
        Tabs,
        TabsContent,
        TabsIndicator,
        TabsList,
        TabsTrigger,
      } from "@/components/ui/tabs"
      import { CopyButton } from "@/components/copy-button"
      import { IconSwap, IconSwapItem } from "@/components/icon-swap"
      import { IconPlaceholder } from "@/registry/icons/icon-placeholder"

      export type PackageManager = "prompt" | "pnpm" | "yarn" | "npm" | "bun"

      const packageManagerAtom = atomWithStorage<PackageManager>(
        "packageManager",
        "pnpm"
      )

      export function usePackageManager() {
        return useAtom(packageManagerAtom)
      }

      /**
       * Props for the CodeBlockCommand component.
       */
      export type CodeBlockCommandProps = {
        /**
         * Natural language instruction for AI agents to install a package or component.
         */
        prompt?: string
        /**
         * Command to execute with pnpm package manager.
         */
        pnpm?: string

        /**
         * Command to execute with yarn package manager.
         */
        yarn?: string

        /**
         * Command to execute with npm package manager.
         */
        npm?: string

        /**
         * Command to execute with bun package manager.
         */
        bun?: string

        /**
         * Callback invoked when a command is successfully copied to clipboard.
         *
         * Receives an object containing the selected package manager and the copied command text.
         * Useful for tracking user interactions or showing custom success notifications.
         *
         * @param data - Object containing copy operation details
         * @param data.packageManager - The package manager that was selected when copying
         * @param data.command - The actual command text that was copied
         *
         * @example
         * ```tsx
         * <CodeBlockCommand
         *   pnpm="pnpm add react"
         *   onCopySuccess={({ packageManager, command }) => {
         *     console.log(`Copied ${command} for ${packageManager}`)
         *   }}
         * />
         * ```
         */
        onCopySuccess?: (data: {
          packageManager: PackageManager
          command: string
        }) => void

        /**
         * Callback invoked when copying to clipboard fails.
         *
         * Receives the error object for debugging or showing custom error messages.
         *
         * @param error - The error that occurred during the copy operation
         *
         * @example
         * ```tsx
         * <CodeBlockCommand
         *   pnpm="pnpm add react"
         *   onCopyError={(error) => {
         *     console.error('Copy failed:', error)
         *   }}
         * />
         * ```
         */
        onCopyError?: (error: Error) => void
      }

      export function CodeBlockCommand({
        prompt,
        pnpm,
        yarn,
        npm,
        bun,
        onCopySuccess,
        onCopyError,
      }: CodeBlockCommandProps) {
        const [packageManager, setPackageManager] = usePackageManager()

        const tabs = useMemo(() => {
          return {
            prompt,
            pnpm,
            yarn,
            npm,
            bun,
          }
        }, [prompt, pnpm, yarn, npm, bun])

        const tabsFiltered = useMemo(
          () => Object.entries(tabs).filter(([, value]) => !!value),
          [tabs]
        )

        return (
          <div className="relative overflow-hidden rounded-xl bg-code">
            <Tabs
              className="gap-0"
              value={packageManager}
              onValueChange={(value) => {
                setPackageManager(value as PackageManager)
              }}
            >
              <ScrollArea.Root className="w-full pr-10 shadow-[inset_0_-1px_0_0] shadow-border">
                <TabsList
                  className={cn(
                    "h-10 max-w-full justify-start rounded-none bg-transparent p-0 pl-4 inset-ring-0 dark:bg-transparent [&_svg]:size-4 [&_svg]:shrink-0 [&_svg]:text-muted-foreground",
                    "[--scroll-area-overflow-x-end:inherit] [--scroll-area-overflow-x-start:inherit]",
                    "mask-linear-[to_right,transparent_0,black_min(2.5rem,var(--scroll-area-overflow-x-start)),black_calc(100%-min(2.5rem,var(--scroll-area-overflow-x-end,2.5rem))),transparent_100%]"
                  )}
                  render={<ScrollArea.Viewport />}
                >
                  <IconSwap>
                    <IconSwapItem className="mr-2" key={packageManager}>
                      {getIconForPackageManager(packageManager)}
                    </IconSwapItem>
                  </IconSwap>

                  {tabsFiltered.map(([key]) => {
                    return (
                      <TabsTrigger
                        key={key}
                        className="h-7 rounded-lg p-0 px-2 font-mono"
                        value={key}
                      >
                        {key}
                      </TabsTrigger>
                    )
                  })}

                  <TabsIndicator className="h-0.5 translate-y-0 rounded-none bg-foreground ring-0 dark:bg-foreground" />
                </TabsList>
              </ScrollArea.Root>

              {tabsFiltered.map(([key, value]) => {
                return (
                  <TabsContent key={key} value={key}>
                    <pre
                      data-pm={key}
                      className="group/tabs-content-pre overscroll-x-contain p-4 leading-6 not-data-[pm=prompt]:overflow-x-auto"
                    >
                      <code
                        data-slot="code-block"
                        data-language="bash"
                        className="font-mono text-sm/none text-muted-foreground group-data-[pm=prompt]/tabs-content-pre:whitespace-normal"
                      >
                        <span className="select-none group-data-[pm=prompt]/tabs-content-pre:hidden">
                          ${" "}
                        </span>
                        {value}
                      </code>
                    </pre>
                  </TabsContent>
                )
              })}
            </Tabs>

            <CopyButton
              className="absolute top-2 right-2 z-10 size-6 rounded-md border-none [&_svg:not([class*='size-'])]:size-3.5"
              variant="ghost"
              size="icon-sm"
              text={tabs[packageManager] || ""}
              onCopySuccess={(copiedCommand) => {
                onCopySuccess?.({
                  packageManager,
                  command: copiedCommand,
                })
              }}
              onCopyError={onCopyError}
            />
          </div>
        )
      }

      function getIconForPackageManager(manager: PackageManager) {
        switch (manager) {
          case "prompt":
            return (
              <IconPlaceholder
                lucide="TextAlignStartIcon"
                tabler="IconAlignLeft"
                hugeicons="TextAlignLeftIcon"
                phosphor="TextAlignLeftIcon"
                remixicon="RiAlignLeft"
              />
            )
          case "pnpm":
            return (
              <svg viewBox="0 0 24 24">
                <path
                  d="M0 0v7.5h7.5V0zm8.25 0v7.5h7.498V0zm8.25 0v7.5H24V0zM8.25 8.25v7.5h7.498v-7.5zm8.25 0v7.5H24v-7.5zM0 16.5V24h7.5v-7.5zm8.25 0V24h7.498v-7.5zm8.25 0V24H24v-7.5z"
                  fill="currentColor"
                />
              </svg>
            )
          case "yarn":
            return (
              <svg viewBox="0 0 24 24">
                <path
                  d="M12 0C5.375 0 0 5.375 0 12s5.375 12 12 12 12-5.375 12-12S18.625 0 12 0zm.768 4.105c.183 0 .363.053.525.157.125.083.287.185.755 1.154.31-.088.468-.042.551-.019.204.056.366.19.463.375.477.917.542 2.553.334 3.605-.241 1.232-.755 2.029-1.131 2.576.324.329.778.899 1.117 1.825.278.774.31 1.478.273 2.015a5.51 5.51 0 0 0 .602-.329c.593-.366 1.487-.917 2.553-.931.714-.009 1.269.445 1.353 1.103a1.23 1.23 0 0 1-.945 1.362c-.649.158-.95.278-1.821.843-1.232.797-2.539 1.242-3.012 1.39a1.686 1.686 0 0 1-.704.343c-.737.181-3.266.315-3.466.315h-.046c-.783 0-1.214-.241-1.45-.491-.658.329-1.51.19-2.122-.134a1.078 1.078 0 0 1-.58-1.153 1.243 1.243 0 0 1-.153-.195c-.162-.25-.528-.936-.454-1.946.056-.723.556-1.367.88-1.71a5.522 5.522 0 0 1 .408-2.256c.306-.727.885-1.348 1.32-1.737-.32-.537-.644-1.367-.329-2.21.227-.602.412-.936.82-1.08h-.005c.199-.074.389-.153.486-.259a3.418 3.418 0 0 1 2.298-1.103c.037-.093.079-.185.125-.283.31-.658.639-1.029 1.024-1.168a.94.94 0 0 1 .328-.06zm.006.7c-.507.016-1.001 1.519-1.001 1.519s-1.27-.204-2.266.871c-.199.218-.468.334-.746.44-.079.028-.176.023-.417.672-.371.991.625 2.094.625 2.094s-1.186.839-1.626 1.881c-.486 1.144-.338 2.261-.338 2.261s-.843.732-.899 1.487c-.051.663.139 1.2.343 1.515.227.343.51.176.51.176s-.561.653-.037.931c.477.25 1.283.394 1.71-.037.31-.31.371-1.001.486-1.283.028-.065.12.111.209.199.097.093.264.195.264.195s-.755.324-.445 1.066c.102.246.468.403 1.066.398.222-.005 2.664-.139 3.313-.296.375-.088.505-.283.505-.283s1.566-.431 2.998-1.357c.917-.598 1.293-.76 2.034-.936.612-.148.57-1.098-.241-1.084-.839.009-1.575.44-2.196.825-1.163.718-1.742.672-1.742.672l-.018-.032c-.079-.13.371-1.293-.134-2.678-.547-1.515-1.413-1.881-1.344-1.997.297-.5 1.038-1.297 1.334-2.78.176-.899.13-2.377-.269-3.151-.074-.144-.732.241-.732.241s-.616-1.371-.788-1.483a.271.271 0 0 0-.157-.046z"
                  fill="currentColor"
                />
              </svg>
            )
          case "npm":
            return (
              <svg viewBox="0 0 24 24">
                <path
                  d="M1.763 0C.786 0 0 .786 0 1.763v20.474C0 23.214.786 24 1.763 24h20.474c.977 0 1.763-.786 1.763-1.763V1.763C24 .786 23.214 0 22.237 0zM5.13 5.323l13.837.019-.009 13.836h-3.464l.01-10.382h-3.456L12.04 19.17H5.113z"
                  fill="currentColor"
                />
              </svg>
            )
          case "bun":
            return (
              <svg viewBox="0 0 24 24">
                <path
                  d="M12 22.596c6.628 0 12-4.338 12-9.688 0-3.318-2.057-6.248-5.219-7.986-1.286-.715-2.297-1.357-3.139-1.89C14.058 2.025 13.08 1.404 12 1.404c-1.097 0-2.334.785-3.966 1.821a49.92 49.92 0 0 1-2.816 1.697C2.057 6.66 0 9.59 0 12.908c0 5.35 5.372 9.687 12 9.687v.001ZM10.599 4.715c.334-.759.503-1.58.498-2.409 0-.145.202-.187.23-.029.658 2.783-.902 4.162-2.057 4.624-.124.048-.199-.121-.103-.209a5.763 5.763 0 0 0 1.432-1.977Zm2.058-.102a5.82 5.82 0 0 0-.782-2.306v-.016c-.069-.123.086-.263.185-.172 1.962 2.111 1.307 4.067.556 5.051-.082.103-.23-.003-.189-.126a5.85 5.85 0 0 0 .23-2.431Zm1.776-.561a5.727 5.727 0 0 0-1.612-1.806v-.014c-.112-.085-.024-.274.114-.218 2.595 1.087 2.774 3.18 2.459 4.407a.116.116 0 0 1-.049.071.11.11 0 0 1-.153-.026.122.122 0 0 1-.022-.083 5.891 5.891 0 0 0-.737-2.331Zm-5.087.561c-.617.546-1.282.76-2.063 1-.117 0-.195-.078-.156-.181 1.752-.909 2.376-1.649 2.999-2.778 0 0 .155-.118.188.085 0 .304-.349 1.329-.968 1.874Zm4.945 11.237a2.957 2.957 0 0 1-.937 1.553c-.346.346-.8.565-1.286.62a2.178 2.178 0 0 1-1.327-.62 2.955 2.955 0 0 1-.925-1.553.244.244 0 0 1 .064-.198.234.234 0 0 1 .193-.069h3.965a.226.226 0 0 1 .19.07c.05.053.073.125.063.197Zm-5.458-2.176a1.862 1.862 0 0 1-2.384-.245 1.98 1.98 0 0 1-.233-2.447c.207-.319.503-.566.848-.713a1.84 1.84 0 0 1 1.092-.11c.366.075.703.261.967.531a1.98 1.98 0 0 1 .408 2.114 1.931 1.931 0 0 1-.698.869v.001Zm8.495.005a1.86 1.86 0 0 1-2.381-.253 1.964 1.964 0 0 1-.547-1.366c0-.384.11-.76.32-1.079.207-.319.503-.567.849-.713a1.844 1.844 0 0 1 1.093-.108c.367.076.704.262.968.534a1.98 1.98 0 0 1 .4 2.117 1.932 1.932 0 0 1-.702.868Z"
                  fill="currentColor"
                />
              </svg>
            )
          default:
            return (
              <IconPlaceholder
                lucide="TerminalIcon"
                tabler="IconTerminal"
                hugeicons="TerminalIcon"
                phosphor="TerminalIcon"
                remixicon="RiTerminalLine"
              />
            )
        }
      }

      /**
       * Result of converting an npm command to all package managers.
       */
      export type ConvertNpmCommandResult = {
        /**
         * Command for pnpm package manager.
         */
        pnpm: string

        /**
         * Command for yarn package manager.
         */
        yarn: string

        /**
         * Command for npm package manager.
         */
        npm: string

        /**
         * Command for bun package manager.
         */
        bun: string
      }

      /**
       * Converts a standard npm command into equivalent commands for pnpm, yarn, npm,
       * and bun. The result can be spread directly into `CodeBlockCommand` props.
       *
       * Supported command patterns:
       * - `npm install <pkg>` -> add commands for each manager
       * - `npx create-<name>` -> create commands for each manager
       * - `npm create <name>` -> create commands for each manager
       * - `npx <command>` -> execute commands for each manager
       * - `npm run <script>` -> run commands for each manager
       *
       * Unrecognized commands are returned as-is for all package managers.
       *
       * @param npmCommand - A standard npm/npx command string.
       * @returns An object with `pnpm`, `yarn`, `npm`, and `bun` command strings.
       *
       * @example
       * ```tsx
       * import { CodeBlockCommand, convertNpmCommand } from "@/components/ncdai/code-block-command"
       *
       * <CodeBlockCommand {...convertNpmCommand("npx shadcn add button")} />
       * ```
       */
      export function convertNpmCommand(npmCommand: string): ConvertNpmCommandResult {
        // npm install
        if (npmCommand.startsWith("npm install")) {
          return {
            pnpm: npmCommand.replaceAll("npm install", "pnpm add"),
            yarn: npmCommand.replaceAll("npm install", "yarn add"),
            npm: npmCommand,
            bun: npmCommand.replaceAll("npm install", "bun add"),
          }
        }

        // npx create- (must be checked before generic npx)
        if (npmCommand.startsWith("npx create-")) {
          return {
            pnpm: npmCommand.replace("npx create-", "pnpm create "),
            yarn: npmCommand.replace("npx create-", "yarn create "),
            npm: npmCommand,
            bun: npmCommand.replace("npx", "bunx --bun"),
          }
        }

        // npm create
        if (npmCommand.startsWith("npm create")) {
          return {
            pnpm: npmCommand.replace("npm create", "pnpm create"),
            yarn: npmCommand.replace("npm create", "yarn create"),
            npm: npmCommand,
            bun: npmCommand.replace("npm create", "bun create"),
          }
        }

        // npx (general)
        if (npmCommand.startsWith("npx")) {
          return {
            pnpm: npmCommand.replace("npx", "pnpm dlx"),
            yarn: npmCommand.replace("npx", "yarn dlx"),
            npm: npmCommand,
            bun: npmCommand.replace("npx", "bunx --bun"),
          }
        }

        // npm run
        if (npmCommand.startsWith("npm run")) {
          return {
            pnpm: npmCommand.replace("npm run", "pnpm"),
            yarn: npmCommand.replace("npm run", "yarn"),
            npm: npmCommand,
            bun: npmCommand.replace("npm run", "bun"),
          }
        }

        return {
          pnpm: npmCommand,
          yarn: npmCommand,
          npm: npmCommand,
          bun: npmCommand,
        }
      }

      ````

      <Step>Update the import paths to match your project setup</Step>
    </Steps>
  </TabsContent>
</CodeTabs>

## Usage

```tsx
import {
  CodeBlockCommand,
  convertNpmCommand,
} from "@/components/code-block-command"
```

```tsx
<CodeBlockCommand
  prompt="Add the button component to my project"
  pnpm="pnpm dlx shadcn add button"
  yarn="yarn dlx shadcn add button"
  npm="npx shadcn add button"
  bun="bunx --bun shadcn add button"
/>
```

Or use `convertNpmCommand` to auto-convert from a standard npm command:

```tsx
<CodeBlockCommand
  prompt="Add the button component to my project"
  {...convertNpmCommand("npx shadcn add button")}
/>
```

## API Reference

### CodeBlockCommand

<TypeTable
  id="type-table-code-block-command.tsx-CodeBlockCommandProps"
  type={{
  "id": "code-block-command.tsx-CodeBlockCommandProps",
  "name": "CodeBlockCommandProps",
  "description": "Props for the CodeBlockCommand component.",
  "entries": [
    {
      "name": "prompt",
      "description": "Natural language instruction for AI agents to install a package or component.",
      "tags": [],
      "type": "string | undefined",
      "simplifiedType": "string",
      "required": false,
      "deprecated": false
    },
    {
      "name": "pnpm",
      "description": "Command to execute with pnpm package manager.",
      "tags": [],
      "type": "string | undefined",
      "simplifiedType": "string",
      "required": false,
      "deprecated": false
    },
    {
      "name": "yarn",
      "description": "Command to execute with yarn package manager.",
      "tags": [],
      "type": "string | undefined",
      "simplifiedType": "string",
      "required": false,
      "deprecated": false
    },
    {
      "name": "npm",
      "description": "Command to execute with npm package manager.",
      "tags": [],
      "type": "string | undefined",
      "simplifiedType": "string",
      "required": false,
      "deprecated": false
    },
    {
      "name": "bun",
      "description": "Command to execute with bun package manager.",
      "tags": [],
      "type": "string | undefined",
      "simplifiedType": "string",
      "required": false,
      "deprecated": false
    },
    {
      "name": "onCopySuccess",
      "description": "Callback invoked when a command is successfully copied to clipboard.\n\nReceives an object containing the selected package manager and the copied command text.\nUseful for tracking user interactions or showing custom success notifications.",
      "tags": [
        {
          "name": "param",
          "text": "data - Object containing copy operation details"
        },
        {
          "name": "param",
          "text": "data.packageManager - The package manager that was selected when copying"
        },
        {
          "name": "param",
          "text": "data.command - The actual command text that was copied"
        },
        {
          "name": "example",
          "text": "```tsx\n<CodeBlockCommand\n  pnpm=\"pnpm add react\"\n  onCopySuccess={({ packageManager, command }) => {\n    console.log(`Copied ${command} for ${packageManager}`)\n  }}\n/>\n```"
        }
      ],
      "type": "((data: { packageManager: PackageManager; command: string; }) => void) | undefined",
      "simplifiedType": "function",
      "required": false,
      "deprecated": false
    },
    {
      "name": "onCopyError",
      "description": "Callback invoked when copying to clipboard fails.\n\nReceives the error object for debugging or showing custom error messages.",
      "tags": [
        {
          "name": "param",
          "text": "error - The error that occurred during the copy operation"
        },
        {
          "name": "example",
          "text": "```tsx\n<CodeBlockCommand\n  pnpm=\"pnpm add react\"\n  onCopyError={(error) => {\n    console.error('Copy failed:', error)\n  }}\n/>\n```"
        }
      ],
      "type": "((error: Error) => void) | undefined",
      "simplifiedType": "function",
      "required": false,
      "deprecated": false
    }
  ]
}}
/>

### convertNpmCommand

Converts a standard npm/npx command into equivalent commands for all package managers. The result can be spread directly into `CodeBlockCommand` props.

<TypeTable
  id="type-table-code-block-command.tsx-ConvertNpmCommandResult"
  type={{
  "id": "code-block-command.tsx-ConvertNpmCommandResult",
  "name": "ConvertNpmCommandResult",
  "description": "Result of converting an npm command to all package managers.",
  "entries": [
    {
      "name": "pnpm",
      "description": "Command for pnpm package manager.",
      "tags": [],
      "type": "string",
      "simplifiedType": "string",
      "required": true,
      "deprecated": false
    },
    {
      "name": "yarn",
      "description": "Command for yarn package manager.",
      "tags": [],
      "type": "string",
      "simplifiedType": "string",
      "required": true,
      "deprecated": false
    },
    {
      "name": "npm",
      "description": "Command for npm package manager.",
      "tags": [],
      "type": "string",
      "simplifiedType": "string",
      "required": true,
      "deprecated": false
    },
    {
      "name": "bun",
      "description": "Command for bun package manager.",
      "tags": [],
      "type": "string",
      "simplifiedType": "string",
      "required": true,
      "deprecated": false
    }
  ]
}}
/>

Supported command patterns:

<div data-table-nowrap="">
  | npm command         | pnpm                 | yarn                 | bun                        |
  | ------------------- | -------------------- | -------------------- | -------------------------- |
  | `npm install`       | `pnpm add`           | `yarn add`           | `bun add`                  |
  | `npx create-<name>` | `pnpm create <name>` | `yarn create <name>` | `bunx --bun create-<name>` |
  | `npm create`        | `pnpm create`        | `yarn create`        | `bun create`               |
  | `npx`               | `pnpm dlx`           | `yarn dlx`           | `bunx --bun`               |
  | `npm run`           | `pnpm`               | `yarn`               | `bun`                      |
</div>

## Examples

### Convert from npm

Use `convertNpmCommand` to avoid manually writing commands for each package manager.

```tsx
"use client"

import {
  CodeBlockCommand,
  convertNpmCommand,
} from "@/components/code-block-command"

export default function CodeBlockCommandConvert() {
  return (
    <div className="w-full max-w-sm">
      <CodeBlockCommand {...convertNpmCommand("npx shadcn add button")} />
    </div>
  )
}

```

### Analytics Tracking

Track user interactions with analytics services like [PostHog](https://posthog.com), [OpenPanel](https://openpanel.dev), or [Google Analytics](https://analytics.google.com).

```tsx {3,12}
<CodeBlockCommand
  {...convertNpmCommand("npx shadcn add button")}
  onCopySuccess={({ packageManager, command }) => {
    trackEvent({
      name: "command_copied",
      properties: {
        packageManager,
        command,
      },
    })
  }}
  onCopyError={(error) => {
    trackEvent({
      name: "command_copy_failed",
      properties: { error: error.message },
    })
  }}
/>
```

<DocSponsors />


Last updated on April 6, 2026