Buttons

Deep Press Button

A real key travel: depth comes from a hard bottom edge, and on press the button drops by exactly that height without nudging its neighbours.

  • button
  • press
  • 3d
  • tactile

Preview

1440pxHost theme

Use it with AI

  1. 1. Copy the link.
  2. 2. Write to your agent in your own words and drop the link into the sentence.
  3. 3. The agent opens the link and installs the component from the registry.

put this in the header: https://vibeui.ru/c/button-045?lang=en

Show the full instructions

What the link says, spelled out. Use it when your agent cannot open links — paste this text instead.

# Install and place "button-045" (Deep Press Button) from VibeUI

## 1. Install first — do not skip, do not recreate
Run this exact command before writing any code:
npx shadcn@latest add https://vibeui.ru/r/button-045.json

Registry item: https://vibeui.ru/r/button-045.json
Installs to: components/vibeui/button-045.tsx (the exact path follows this project's components.json aliases).
npm dependencies: none.
Registry dependencies: none.

Install it from the registry. Do not recreate it from the description,
do not substitute a similar component from another library, and do not
rewrite it to match the project's existing style.

## 2. What it is
A real key travel: depth comes from a hard bottom edge, and on press the button drops by exactly that height without nudging its neighbours.

A button with real travel. A hard, unblurred edge sits beneath it — not a shadow but the side of a keycap; a light inset highlight on top adds the plastic. On press the edge collapses and the button drops by its height: the total stays constant, so neighbouring elements never shift. Zero dependencies, one file.

## 3. How to use it
import { Button045 } from "@/components/vibeui/button-045"

<Button045 depth={5} onClick={submit}>Press me</Button045>

Read the installed file for the full prop list.

## 4. Where to place it
This is a small inline component. Put it exactly where the user asked,
inside the existing markup. Do not create a new page, section or
wrapper for it. If a similar control already sits in that spot,
replace it instead of adding a second one.

Placement: ___
(The user fills this line in. If it is still blank, ask where to put it
instead of guessing.)

## 5. Keep exactly as installed
- the equality of the travel and the edge height: if they diverge, pressing the button starts moving its neighbours
- the unblurred bottom edge — a blurred shadow gives float, not the side of a keycap
- the inset highlight on top: without it the plastic reads as a flat fill
- the short .08s transition: a long press animation feels like input lag
- the depth variable as the single source of depth — the same value drives the shift
- the darker edge relative to the face: an identical colour kills the volume

## 6. You may change
- the label
- the travel depth through the depth prop, in pixels
- the face colour through the accent prop
- the onClick handler and the rest of the native button props
- the edge colour through the --vibeui-button-045-edge variable in the style block

## 7. Rules
- Do not set depth above 10px: the button starts to look like a box and the travel feels sluggish.
- Remember the bottom spacing of the neighbours: the edge takes room, and an element placed flush will cover it.
- Do not make the edge colour transparent — that removes the very volume the component exists for.
- Do not lift the CSS variables into globals.css: the component has to stay a single file.

## 8. Verify
- it renders with no console errors;
- it looks like the preview on the VibeUI page you copied this from;
- if it does not, you changed something listed in section 5 — put it back.

For developers

npx shadcn@latest add https://vibeui.ru/r/button-045.json
https://vibeui.ru/r/button-045.json

Компонент самодостаточен: один файл, без зависимостей, собственная палитра в локальных переменных --vibeui-button-045-*. Серверный компонент. Объём даёт box-shadow без размытия высотой --vibeui-button-045-depth (проп depth в пикселях); на :active грань обнуляется, а кнопка сдвигается вниз ровно на ту же величину, поэтому суммарная высота пятна постоянна и ряд кнопок не дёргается. Внутренний блик сверху — второй inset-слой той же тени.

Component source

The same file your agent installs. Here in case you would rather copy it by hand.

import type { ComponentPropsWithoutRef, CSSProperties } from "react"

export type Button045Props = ComponentPropsWithoutRef<"button"> & {
  /** Высота нижней грани в пикселях: глубина хода клавиши. */
  depth?: number
  accent?: string
}

// Идея компонента: настоящий ход клавиши. Объём даёт не размытая тень,
// а жёсткая нижняя грань box-shadow без блюра; на :active кнопка опускается
// ровно на её высоту, а грань исчезает — сумма высот постоянна, поэтому
// соседи в ряду не дёргаются. Внутренний блик сверху добавляет пластик.
const STYLES = `
:where([data-vibeui-block="button-045"]){
--vibeui-button-045-depth:5px;
--vibeui-button-045-accent:oklch(0.62 0.19 55);
--vibeui-button-045-edge:oklch(0.44 0.15 55);
--vibeui-button-045-fg:oklch(0.99 0.02 55);
--vibeui-button-045-font:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
}
[data-vibeui-block="button-045"]{
appearance:none;border:0;cursor:pointer;box-sizing:border-box;
display:inline-flex;align-items:center;gap:0.5rem;
height:2.75rem;padding:0 1.25rem;border-radius:0.75rem;
background:var(--vibeui-button-045-accent);color:var(--vibeui-button-045-fg);
font-family:var(--vibeui-button-045-font);font-size:0.9375rem;font-weight:700;line-height:1;
box-shadow:
0 var(--vibeui-button-045-depth) 0 0 var(--vibeui-button-045-edge),
inset 0 1px 0 0 oklch(1 0 0 / 28%);
transform:translateY(0);
transition:transform .08s ease,box-shadow .08s ease,filter .16s ease;
}
[data-vibeui-block="button-045"]:hover:not(:disabled){filter:brightness(1.05)}
/* Ход клавиши: смещение равно исчезнувшей грани, общая высота не меняется. */
[data-vibeui-block="button-045"]:active:not(:disabled){
transform:translateY(var(--vibeui-button-045-depth));
box-shadow:0 0 0 0 var(--vibeui-button-045-edge),inset 0 1px 0 0 oklch(1 0 0 / 18%);
}
[data-vibeui-block="button-045"]:focus-visible{outline:2px solid var(--vibeui-button-045-edge);outline-offset:3px}
[data-vibeui-block="button-045"]:disabled{cursor:not-allowed;opacity:.55}
[data-vibeui-block="button-045"] [data-part="key"]{
flex:none;width:0.875rem;height:0.875rem;border-radius:0.25rem;
background:oklch(1 0 0 / 30%);box-shadow:inset 0 -1.5px 0 0 oklch(0 0 0 / 18%);
}
@media (prefers-reduced-motion:reduce){[data-vibeui-block="button-045"]{transition:none!important}}
`

/**
 * Кнопка с эффектом нажатия: жёсткая нижняя грань и настоящий ход клавиши.
 * Один файл, ноль зависимостей, собственная палитра.
 */
export function Button045({
  depth = 5,
  accent,
  type = "button",
  className,
  style,
  children = "Нажми меня",
  ...props
}: Button045Props) {
  const palette = {
    "--vibeui-button-045-depth": `${depth}px`,
    ...(accent ? { "--vibeui-button-045-accent": accent } : null),
    ...style,
  } as CSSProperties

  return (
    <>
      <style href="vibeui-button-045" precedence="medium">
        {STYLES}
      </style>
      <button
        {...props}
        type={type}
        data-vibeui-block="button-045"
        className={className}
        style={palette}
      >
        <span data-part="key" aria-hidden="true" />
        {children}
      </button>
    </>
  )
}