# Button 3D Press — Animated React Button

> A raised key with a real edge and cast shadow: it lifts slightly on hover, sinks hard on press and bounces back on release.

- Category: [Buttons](https://pixelpapa.com/components/buttons.md)
- Tags: button, 3d, press, depth, tactile
- Dependencies: lucide-react (plus React and Tailwind CSS v4)
- Last updated: 2026-11-13
- Live preview: https://pixelpapa.com/components/buttons/button-3d-press

## Install

```bash
npx shadcn@latest add "https://pixelpapa.com/r/button-3d-press.json"
```

The file is written to `components/pixelpapa/button-3d-press.tsx`. To install manually, run `npm install lucide-react` and copy the source below into your project. It imports `cn` from `@/lib/utils`, which every shadcn project has.

## Source

```tsx
"use client";

import { Play, Rocket } from "lucide-react";
import type { ComponentProps, CSSProperties } from "react";
import { cn } from "@/lib/utils";

type PressButtonProps = ComponentProps<"button"> & {
  /** Face colour (any CSS colour). The edge is derived from it. */
  color?: string;
  /** Resting height of the face above its base, in px. */
  depth?: number;
  /** Classes for the face: text colour, padding, height. */
  faceClassName?: string;
};

export function PressButton({
  color = "var(--primary)",
  depth = 6,
  faceClassName,
  className,
  children,
  ...props
}: PressButtonProps) {
  return (
    <button
      style={{ "--pp-c": color, "--pp-d": `${depth}px` } as CSSProperties}
      className={cn(
        "group relative inline-flex rounded-xl text-sm font-semibold outline-offset-4 select-none [-webkit-tap-highlight-color:transparent]",
        className,
      )}
      {...props}
    >
      {/* Cast shadow: spreads when the face lifts, tucks in when pressed. */}
      <span
        aria-hidden
        className="absolute inset-0 translate-y-1 rounded-[inherit] bg-black/25 blur-[5px] transition-[translate,opacity] duration-300 group-hover:translate-y-2 group-active:translate-y-0 group-active:opacity-60 group-active:duration-75 dark:bg-black/60"
      />
      {/* Edge: darker at the corners, like light falling off a curved side. */}
      <span
        aria-hidden
        className="absolute inset-0 rounded-[inherit] ring-1 ring-foreground/10 ring-inset"
        style={{
          background:
            "linear-gradient(to right, color-mix(in oklch, var(--pp-c) 52%, black), color-mix(in oklch, var(--pp-c) 70%, black) 10%, color-mix(in oklch, var(--pp-c) 70%, black) 90%, color-mix(in oklch, var(--pp-c) 52%, black))",
        }}
      />
      <span
        className={cn(
          "relative inline-flex h-12 -translate-y-[var(--pp-d)] items-center gap-2 rounded-[inherit] px-6 text-primary-foreground shadow-[inset_0_1px_0_rgb(255_255_255/0.25)] ring-1 ring-foreground/10 transition-[translate] duration-300 ease-[cubic-bezier(0.3,0.7,0.4,1.6)] ring-inset group-hover:-translate-y-[calc(var(--pp-d)_+_2px)] group-active:-translate-y-px group-active:duration-75 group-active:ease-out motion-reduce:transition-none",
          faceClassName,
        )}
        style={{ background: "var(--pp-c)" }}
      >
        {children}
      </span>
    </button>
  );
}

export default function Button3dPressDemo() {
  return (
    <div className="flex flex-wrap items-center justify-center gap-6 pt-2">
      <PressButton>
        <Rocket className="size-4" />
        Deploy to production
      </PressButton>
      <PressButton color="var(--secondary)" faceClassName="text-secondary-foreground">
        Save as draft
      </PressButton>
      <PressButton
        aria-label="Play preview"
        color="oklch(0.72 0.17 155)"
        depth={8}
        className="rounded-full"
        faceClassName="size-14 justify-center px-0 text-white"
      >
        <Play className="size-5 fill-current" />
      </PressButton>
    </div>
  );
}
```

## AI prompt

```text
Add the "Button 3D Press" component from PixelPapa UI to this project.

What it is: A raised key with a real edge and cast shadow: it lifts slightly on hover, sinks hard on press and bounces back on release.
Category: Buttons. Depends on: lucide-react.

1. Install it with the shadcn CLI:
   npx shadcn@latest add "https://pixelpapa.com/r/button-3d-press.json"
   (If the CLI is unavailable, fetch that URL, write files[0].content to components/pixelpapa/button-3d-press.tsx and install the listed dependencies.)
2. Import it from "@/components/pixelpapa/button-3d-press" and place it where I describe below.
3. Keep its animation timings and accessibility attributes. Replace the demo copy and data with content that fits my product, and use my existing theme tokens (bg-background, text-foreground, bg-primary, border-border) rather than hard-coded colours.

Where to use it: <describe the page and position here>
```

## More buttons

- [Button Async States](https://pixelpapa.com/components/buttons/button-async-states.md) (Pro): Runs a promise and morphs through idle, a collapsed spinner, then a success or error label, animating its width between each.
- [Button Border Beam](https://pixelpapa.com/components/buttons/button-border-beam.md) (Pro): A comet of light laps the button's border on a loop, with a soft halo that follows the head of the beam.
- [Button Confetti Burst](https://pixelpapa.com/components/buttons/button-confetti-burst.md) (Pro): Throws a fan of DOM confetti from the exact point you clicked; pieces arc up, tumble and fall under gravity. No canvas.
- [Button Copy Feedback](https://pixelpapa.com/components/buttons/button-copy-feedback.md) (Pro): Copies a value to the clipboard, then swaps its icon for a drawn check and rolls the label to "Copied" before settling back.
- [Button Gradient Border Glow](https://pixelpapa.com/components/buttons/button-gradient-border-glow.md) (Pro): A flowing gradient outline with a blurred twin underneath; the glow brightens on hover and leans toward the cursor.
- [Button Group Segmented](https://pixelpapa.com/components/buttons/button-group-segmented.md) (Pro): A segmented control whose pill stretches like jelly: its leading edge races ahead and the trailing edge catches up on a softer spring.
