# Snippet

> A one-line command with a $ prompt and a copy button that morphs into a check. When the command changes (pnpm ↔ npm) the text swaps and the width springs, so the copy button glides instead of jumping.

- Tier: Free (MIT)
- Interaction: Press
- Page: https://eased.dev/components/snippet
- Installs: motion, shiki
- Registry: https://eased.dev/r/snippet.json

## Install

```bash
npx shadcn add https://eased.dev/r/snippet.json
```

A one-line command with a `$` prompt and a copy button.

**Motion signature:** when the command changes (pnpm ↔ npm) the old text lifts away and the new one rises in while the pill's width springs to fit, so the copy button glides instead of jumping; copying morphs the icon into a check.

## When to use

- Install and run commands in docs, onboarding and empty states.
- Anything a reader pastes into a terminal as one line.

## When not to use

- Multi-line code: use [Code Block](/components/code-block). A choice of package manager shown as tabs: use [Code Tabs](/components/code-tabs).

## Usage

```tsx install.tsx
import { Snippet } from "@/components/eased/snippet/snippet";
import { useChoice } from "@/components/eased/_primitives/code-core/choice";
import { PACKAGE_MANAGERS, packageCommand, type PackageManager } from "@/components/eased/code-tabs/code-tabs";

const [pm] = useChoice("package-manager", "pnpm", PACKAGE_MANAGERS);
<Snippet text={packageCommand(pm as PackageManager, { dlx: "shadcn add https://eased.dev/r/code-block.json" })} />
```

## Props

| Prop | Default | |
|---|---|---|
| `text` | | The command. Changing it swaps the text and springs the width. |
| `prefix` | `"$"` | Shown, never copied. `null` hides it. |
| `lang` | `"bash"` | Grammar for the command. |
| `label` | `"Copy command"` | Accessible name of the copy button. |
| `onCopy` | | `(text) => void`. |

A command wider than its container scrolls sideways under 20px edge fades. Reduced motion: a 100ms cross-fade and an instant width.

## Example

`components/eased/snippet/snippet-demo.tsx`

```tsx
"use client";

import { useChoice } from "../_primitives/code-core/choice";
import { PACKAGE_MANAGERS, packageCommand, type PackageManager } from "../code-tabs/code-tabs";
import { DemoFrame } from "../lib/demo-frame";
import { Segmented } from "../segmented/segmented";
import { Snippet } from "./snippet";

const OPTIONS = PACKAGE_MANAGERS.map((pm) => ({ value: pm, label: pm }));

/** An install card: pick a package manager (shared with every Code Tabs on the page) and both commands follow. */
export function SnippetDemo() {
  const [pm, setPm] = useChoice("package-manager", "pnpm", PACKAGE_MANAGERS);
  const manager = pm as PackageManager;
  return (
    <DemoFrame title="Install" actions={<Segmented options={OPTIONS} value={manager} onValueChange={setPm} aria-label="Package manager" />}>
      <ol className="flex min-h-0 flex-1 flex-col gap-6 overflow-y-auto p-4">
        <li className="flex min-w-0 flex-col gap-2">
          <div>
            <p className="text-ui font-medium text-text">Add the component</p>
            <p className="text-ui-sm text-text-secondary">Copies the source into components/eased.</p>
          </div>
          <Snippet className="self-start" text={packageCommand(manager, { dlx: "shadcn add https://eased.dev/r/code-block.json" })} />
        </li>
        <li className="flex min-w-0 flex-col gap-2">
          <div>
            <p className="text-ui font-medium text-text">Start your dev server</p>
            <p className="text-ui-sm text-text-secondary">Then open localhost:3000.</p>
          </div>
          <Snippet className="self-start" text={packageCommand(manager, { run: "dev" })} />
        </li>
        <li className="flex min-w-0 flex-col gap-2">
          <div>
            <p className="text-ui font-medium text-text">Or clone the starter</p>
            <p className="text-ui-sm text-text-secondary">A Next.js app with every free component.</p>
          </div>
          <Snippet className="self-start" text="git clone https://github.com/eased-dev/starter.git my-app" />
        </li>
      </ol>
    </DemoFrame>
  );
}
```
