Buttons
Scale Ramp Button
An sm/md/lg/xl size ramp driven by a single number: height, padding, type size, radius and icon are all derived through calc from one step.
- button
- size
- scale
- tokens
Preview
Use it with AI
- 1. Copy the link.
- 2. Write to your agent in your own words and drop the link into the sentence.
- 3. The agent opens the link and installs the component from the registry.
put this in the header: https://vibeui.ru/c/button-039?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-039" (Scale Ramp 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-039.json
Registry item: https://vibeui.ru/r/button-039.json
Installs to: components/vibeui/button-039.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
An sm/md/lg/xl size ramp driven by a single number: height, padding, type size, radius and icon are all derived through calc from one step.
A button whose size is a single number. Four values of the size prop set a multiplier, and calc derives the whole geometry from it, the icon and the focus ring width included. Letter spacing is divided by the step, so the large sizes never look loose. Zero dependencies, one file.
## 3. How to use it
import { Button039 } from "@/components/vibeui/button-039"
<Button039 size="lg" onClick={addBlock}>
Add block
</Button039>
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 single step multiplier as the source of the whole geometry: hardcoding values for one size breaks the ramp
- the icon and the focus ring taking part in the ramp — they must grow with the type size
- dividing letter spacing by the step: at a large size the original tracking reads as spaced-out lettering
- the four size values as a ramp, not as four independent styles
- the --vibeui-button-039-unit base unit: every size's height is derived from it
- the 0.82 / 1 / 1.22 / 1.5 step ratios — chosen so that neighbouring sizes differ without competing
## 6. You may change
- the label
- the size through the size prop (sm, md, lg or xl)
- the accent colour through the accent prop
- the onClick handler and the rest of the native button props
- the base unit and the ramp multipliers to match your typography
## 7. Rules
- Do not set a height or padding directly for one size: it drops out of the ramp and breaks the row.
- Do not add a fifth size by copying rules — one new line with its own step value is enough.
- Do not push sm below 0.8: the icon and the focus ring stop landing on the pixel grid.
- 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-039.jsonhttps://vibeui.ru/r/button-039.jsonКомпонент самодостаточен: один файл, без зависимостей, собственная палитра в локальных переменных --vibeui-button-039-*. Серверный компонент. Переменная --vibeui-button-039-step переключается data-атрибутом size и умножает базовые метрики: высоту (--vibeui-button-039-unit), паддинг, кегль, радиус, толщину обводки фокуса и размер значка. Разрядка, наоборот, делится на шаг — крупный кегль требует меньшего трекинга. Новый размер добавляется одной строкой с новым значением step.
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 Button039Props = ComponentPropsWithoutRef<"button"> & {
size?: "sm" | "md" | "lg" | "xl"
accent?: string
}
// Идея компонента: размер — это одно число, а не четыре набора правил.
// Вся геометрия (высота, паддинги, кегль, радиус, значок, разрядка) считается
// из --vibeui-button-039-step через calc, поэтому шкала остаётся
// пропорциональной, а новый размер добавляется одной строкой.
const STYLES = `
:where([data-vibeui-block="button-039"]){
--vibeui-button-039-step:1;
--vibeui-button-039-unit:2rem;
--vibeui-button-039-accent:oklch(0.52 0.17 320);
--vibeui-button-039-fg:oklch(0.99 0.01 320);
--vibeui-button-039-font:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
}
[data-vibeui-block="button-039"]{
appearance:none;border:0;cursor:pointer;box-sizing:border-box;
display:inline-flex;align-items:center;justify-content:center;
gap:calc(0.375rem * var(--vibeui-button-039-step));
height:calc(var(--vibeui-button-039-unit) * var(--vibeui-button-039-step));
padding:0 calc(0.875rem * var(--vibeui-button-039-step));
border-radius:calc(0.5rem * var(--vibeui-button-039-step));
background:var(--vibeui-button-039-accent);color:var(--vibeui-button-039-fg);
font-family:var(--vibeui-button-039-font);
font-size:calc(0.8125rem * var(--vibeui-button-039-step));
font-weight:600;line-height:1;
letter-spacing:calc(0.01em / var(--vibeui-button-039-step));
transition:filter .16s ease;
}
[data-vibeui-block="button-039"][data-size="sm"]{--vibeui-button-039-step:0.82}
[data-vibeui-block="button-039"][data-size="md"]{--vibeui-button-039-step:1}
[data-vibeui-block="button-039"][data-size="lg"]{--vibeui-button-039-step:1.22}
[data-vibeui-block="button-039"][data-size="xl"]{--vibeui-button-039-step:1.5}
[data-vibeui-block="button-039"]:hover:not(:disabled){filter:brightness(1.07)}
[data-vibeui-block="button-039"]:focus-visible{
outline:calc(2px * var(--vibeui-button-039-step)) solid var(--vibeui-button-039-accent);
outline-offset:calc(2px * var(--vibeui-button-039-step));
}
[data-vibeui-block="button-039"]:disabled{cursor:not-allowed;opacity:.5}
/* Значок тоже часть шкалы: он растёт вместе с кеглем, а не остаётся 16px. */
[data-vibeui-block="button-039"] [data-part="mark"]{
position:relative;flex:none;
width:calc(0.75rem * var(--vibeui-button-039-step));
height:calc(0.75rem * var(--vibeui-button-039-step));
}
[data-vibeui-block="button-039"] [data-part="mark"]::before,
[data-vibeui-block="button-039"] [data-part="mark"]::after{
content:"";position:absolute;background:currentColor;border-radius:9999px;
}
[data-vibeui-block="button-039"] [data-part="mark"]::before{
left:0;top:50%;width:100%;height:calc(1.5px * var(--vibeui-button-039-step));transform:translateY(-50%);
}
[data-vibeui-block="button-039"] [data-part="mark"]::after{
left:50%;top:0;height:100%;width:calc(1.5px * var(--vibeui-button-039-step));transform:translateX(-50%);
}
@media (prefers-reduced-motion:reduce){[data-vibeui-block="button-039"]{transition:none!important}}
`
/**
* Размерная шкала sm/md/lg/xl из одной переменной: вся геометрия на calc.
* Один файл, ноль зависимостей, собственная палитра.
*/
export function Button039({
size = "md",
accent,
type = "button",
className,
style,
children = "Добавить блок",
...props
}: Button039Props) {
const palette = {
...(accent ? { "--vibeui-button-039-accent": accent } : null),
...style,
} as CSSProperties
return (
<>
<style href="vibeui-button-039" precedence="medium">
{STYLES}
</style>
<button
{...props}
type={type}
data-vibeui-block="button-039"
data-size={size}
className={className}
style={palette}
>
<span data-part="mark" aria-hidden="true" />
{children}
</button>
</>
)
}