Buttons
Mobile Checkout Bar
A phone's bottom bar button: full width, the price inside and safe-area padding for the home indicator.
- button
- mobile
- checkout
- safe-area
Preview
1440pxHost theme
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-020?lang=en
Delivered tomorrow, pay on arrival
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-020" (Mobile Checkout Bar) 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-020.json
Registry item: https://vibeui.ru/r/button-020.json
Installs to: components/vibeui/button-020.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 phone's bottom bar button: full width, the price inside and safe-area padding for the home indicator.
A phone bottom bar: a full-width button with the price inside, a note below and padding for the home indicator. Zero dependencies, one file, no client JS.
## 3. How to use it
import { Button020 } from "@/components/vibeui/button-020"
<Button020 label="Place order" price="$59" hint="Delivered tomorrow" />
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 local --vibeui-button-020-* palette — do not swap it for your theme tokens
- env(safe-area-inset-bottom): without it the button slides under the iPhone home bar
- the price inside the button: at this step the sum drives the decision
- the 3rem height — the bottom button is pressed with a thumb
- the bar's top border separating it from scrolling content
- the note under the button rather than small print inside it
## 6. You may change
- label, price and hint
- the accent through the accent prop
- the button radius for your style
- the bar width in the caller
## 7. Rules
- Positioning is not part of the component: fixed placement belongs to the caller.
- The price must match the order total: a mismatch here reads as a trick.
- Do not squeeze a second action into the bar: the space belongs to the main one.
- 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-020.jsonhttps://vibeui.ru/r/button-020.jsonКомпонент самодостаточен: один файл, без зависимостей, собственная палитра в локальных переменных --vibeui-button-020-*. Серверный: хуков нет. Нижний отступ считается как базовый плюс env(safe-area-inset-bottom): без него на iPhone край кнопки уходит под системную черту. Высота кнопки 3rem, цена выровнена по правому краю табличными цифрами.
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 Button020Props = Omit<
ComponentPropsWithoutRef<"div">,
"children"
> & {
label?: string
price?: string
hint?: string
accent?: string
}
// Идея компонента: кнопка нижней панели телефона. Она во всю ширину, высотой
// 3rem и с отступом на домашнюю полоску через safe-area — иначе на iPhone
// нижний край кнопки уходит под системную черту. Цена стоит в самой кнопке:
// на этом шаге решение принимают по сумме, а не по слову «оплатить».
const STYLES = `
:where([data-vibeui-block="button-020"]){
--vibeui-button-020-accent:oklch(0.55 0.17 265);
--vibeui-button-020-fg:oklch(0.99 0.01 265);
--vibeui-button-020-muted:oklch(0.55 0.014 265);
--vibeui-button-020-bg:oklch(1 0 0);
--vibeui-button-020-border:oklch(0.92 0.005 265);
--vibeui-button-020-font:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
}
[data-vibeui-block="button-020"]{
display:flex;flex-direction:column;gap:0.5rem;
width:100%;max-width:24rem;box-sizing:border-box;
padding:0.75rem 0.875rem calc(0.75rem + env(safe-area-inset-bottom,0px));
border-top:1px solid var(--vibeui-button-020-border);
background:var(--vibeui-button-020-bg);
font-family:var(--vibeui-button-020-font);
}
[data-vibeui-block="button-020"] button{
appearance:none;border:0;cursor:pointer;
display:flex;align-items:center;justify-content:space-between;gap:0.75rem;
width:100%;height:3rem;padding:0 1rem;box-sizing:border-box;
border-radius:0.75rem;
background:var(--vibeui-button-020-accent);color:var(--vibeui-button-020-fg);
font:inherit;font-size:0.9375rem;font-weight:650;line-height:1;
}
[data-vibeui-block="button-020"] button:hover{filter:brightness(0.96)}
[data-vibeui-block="button-020"] button:focus-visible{outline:2px solid var(--vibeui-button-020-accent);outline-offset:2px}
/* Цена в самой кнопке: решение принимают по сумме, а не по глаголу. */
[data-vibeui-block="button-020"] [data-part="price"]{font-variant-numeric:tabular-nums}
[data-vibeui-block="button-020"] [data-part="hint"]{
text-align:center;font-size:0.75rem;line-height:1.35;color:var(--vibeui-button-020-muted);
}
@media (prefers-reduced-motion:reduce){[data-vibeui-block="button-020"] *{animation:none!important;transition:none!important}}
`
/**
* Кнопка нижней панели телефона: во всю ширину, с ценой и safe-area.
* Один файл, ноль зависимостей, собственная палитра.
*/
export function Button020({
label = "Оформить заказ",
price = "4 900 ₽",
hint = "Доставка завтра, оплата при получении",
accent,
className,
style,
...props
}: Button020Props) {
const palette = {
...(accent ? { "--vibeui-button-020-accent": accent } : null),
...style,
} as CSSProperties
return (
<>
<style href="vibeui-button-020" precedence="medium">
{STYLES}
</style>
<div
{...props}
data-vibeui-block="button-020"
className={className}
style={palette}
>
<button type="button">
{label}
{price ? <span data-part="price">{price}</span> : null}
</button>
{hint ? <p data-part="hint">{hint}</p> : null}
</div>
</>
)
}