Feedback
Rich Toast
A toast with an explanation: two lines of text under the heading and the actions on their own row so they never squeeze the title on a narrow screen.
- toast
- actions
- invite
- clamp
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/toast-007?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 "toast-007" (Rich Toast) 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/toast-007.json
Registry item: https://vibeui.ru/r/toast-007.json
Installs to: components/vibeui/toast-007.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 toast with an explanation: two lines of text under the heading and the actions on their own row so they never squeeze the title on a narrow screen.
A toast with a two-line description and a pair of actions under the text. Zero dependencies, one file, no client JS.
## 3. How to use it
import { Toast007 } from "@/components/vibeui/toast-007"
<Toast007
title="Team invitation"
description="Maria invites you to the «Catalog» project."
primaryLabel="Accept"
secondaryLabel="Later"
/>
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-toast-007-* palette — do not swap it for your theme tokens
- the two-line clamp on the description: a third line turns the toast into a letter
- the actions on their own row — inline with the heading they squeeze it down to one word
- the different weight of the primary and secondary action: two identical buttons make people choose twice
- the aria-label on the close button — an unnamed icon is useless to a screen reader
- the card's own light surface: without it the dark text disappears on a dark background
## 6. You may change
- the heading through title and the copy through description
- the button captions through primaryLabel and secondaryLabel
- the glyph in the left square — a character or your own icon
- the accent through the --vibeui-toast-007-tone variable
## 7. Rules
- The two-line clamp relies on -webkit-line-clamp: in very old engines the text simply will not be cut.
- An empty secondaryLabel removes the second button without breaking the layout.
- The close button does not dismiss the card itself — the caller attaches the handler.
- 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/toast-007.jsonhttps://vibeui.ru/r/toast-007.jsonКомпонент самодостаточен: один файл, без зависимостей, собственная палитра в локальных переменных --vibeui-toast-007-*. Серверный: хуков нет. Раскладка — сетка из трёх колонок: значок занимает три ряда, заголовок и крестик стоят в первом, описание и действия растянуты на две колонки. Описание обрезано на двух строках через -webkit-line-clamp: третья строка превращает уведомление в письмо. Действия вынесены вниз, поэтому на узком экране заголовок не сжимается до одного слова.
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 Toast007Props = Omit<
ComponentPropsWithoutRef<"div">,
"children" | "title"
> & {
title?: string
/** Описание обрезается ровно на двух строках: третья съедает карточку. */
description?: string
primaryLabel?: string
secondaryLabel?: string
onPrimary?: () => void
onSecondary?: () => void
}
// Идея компонента: уведомление, которому есть что объяснить. Описание живёт
// ровно в двух строках (-webkit-line-clamp), а действия вынесены на отдельную
// строку под текстом — так они не сжимают заголовок на узком экране.
const STYLES = `
:where([data-vibeui-block="toast-007"]){
--vibeui-toast-007-bg:oklch(1 0 0);
--vibeui-toast-007-fg:oklch(0.23 0.014 265);
--vibeui-toast-007-muted:oklch(0.54 0.014 265);
--vibeui-toast-007-border:oklch(0.9 0.006 265);
--vibeui-toast-007-tone:oklch(0.58 0.15 285);
--vibeui-toast-007-soft:oklch(0.95 0.03 285);
--vibeui-toast-007-radius:1rem;
--vibeui-toast-007-font:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
}
[data-vibeui-block="toast-007"]{
display:grid;grid-template-columns:auto 1fr auto;gap:0.25rem 0.75rem;
width:100%;max-width:25rem;box-sizing:border-box;
padding:0.9375rem;
border:1px solid var(--vibeui-toast-007-border);
border-radius:var(--vibeui-toast-007-radius);
background:var(--vibeui-toast-007-bg);color:var(--vibeui-toast-007-fg);
font-family:var(--vibeui-toast-007-font);
box-shadow:0 22px 46px -28px oklch(0.2 0.02 265 / 50%);
}
[data-vibeui-block="toast-007"] [data-part="glyph"]{
grid-row:1 / span 3;flex:none;
display:flex;align-items:center;justify-content:center;
width:2.25rem;height:2.25rem;border-radius:0.75rem;
background:var(--vibeui-toast-007-soft);color:var(--vibeui-toast-007-tone);
font-size:1rem;line-height:1;
}
[data-vibeui-block="toast-007"] [data-part="title"]{margin:0;font-size:0.9375rem;font-weight:650;line-height:1.3}
/* Две строки — потолок: третья превращает уведомление в письмо. */
[data-vibeui-block="toast-007"] [data-part="description"]{
grid-column:2 / span 2;margin:0.1875rem 0 0;
font-size:0.8125rem;line-height:1.45;color:var(--vibeui-toast-007-muted);
display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;
overflow:hidden;
}
[data-vibeui-block="toast-007"] [data-part="actions"]{
grid-column:2 / span 2;display:flex;flex-wrap:wrap;gap:0.5rem;margin-top:0.625rem;
}
[data-vibeui-block="toast-007"] [data-part="primary"],
[data-vibeui-block="toast-007"] [data-part="secondary"]{
appearance:none;cursor:pointer;
height:1.9375rem;padding:0 0.75rem;border-radius:0.5rem;
font:inherit;font-size:0.8125rem;font-weight:640;
transition:background-color .16s ease,color .16s ease;
}
[data-vibeui-block="toast-007"] [data-part="primary"]{border:0;background:var(--vibeui-toast-007-tone);color:oklch(0.99 0.01 285)}
[data-vibeui-block="toast-007"] [data-part="primary"]:hover{background:color-mix(in oklab,var(--vibeui-toast-007-tone) 88%,black)}
[data-vibeui-block="toast-007"] [data-part="secondary"]{
border:1px solid var(--vibeui-toast-007-border);background:transparent;color:var(--vibeui-toast-007-muted);
}
[data-vibeui-block="toast-007"] [data-part="secondary"]:hover{color:var(--vibeui-toast-007-fg);background:oklch(0.96 0.004 265)}
[data-vibeui-block="toast-007"] [data-part="close"]{
appearance:none;cursor:pointer;border:0;background:transparent;
align-self:start;width:1.5rem;height:1.5rem;border-radius:0.375rem;
color:var(--vibeui-toast-007-muted);font:inherit;font-size:1rem;line-height:1;
}
[data-vibeui-block="toast-007"] [data-part="close"]:hover{background:oklch(0.95 0.004 265);color:var(--vibeui-toast-007-fg)}
[data-vibeui-block="toast-007"] [data-part="primary"]:focus-visible,
[data-vibeui-block="toast-007"] [data-part="secondary"]:focus-visible,
[data-vibeui-block="toast-007"] [data-part="close"]:focus-visible{outline:2px solid var(--vibeui-toast-007-tone);outline-offset:2px}
@media (prefers-reduced-motion:reduce){[data-vibeui-block="toast-007"] *{animation:none!important;transition:none!important}}
`
/**
* Уведомление с описанием на две строки и действиями отдельной строкой.
* Один файл, ноль зависимостей, собственная палитра.
*/
export function Toast007({
title = "Приглашение в команду",
description = "Мария Гурова зовёт вас в проект «Каталог». Доступ на запись выдаётся сразу после согласия, отозвать его можно в настройках.",
primaryLabel = "Принять",
secondaryLabel = "Позже",
onPrimary,
onSecondary,
className,
style,
...props
}: Toast007Props) {
return (
<>
<style href="vibeui-toast-007" precedence="medium">
{STYLES}
</style>
<div
{...props}
data-vibeui-block="toast-007"
role="status"
aria-live="polite"
className={className}
style={style as CSSProperties}
>
<span data-part="glyph" aria-hidden="true">
✉
</span>
<p data-part="title">{title}</p>
<button
data-part="close"
type="button"
aria-label="Закрыть уведомление"
>
×
</button>
<p data-part="description">{description}</p>
<div data-part="actions">
<button data-part="primary" type="button" onClick={onPrimary}>
{primaryLabel}
</button>
{secondaryLabel ? (
<button data-part="secondary" type="button" onClick={onSecondary}>
{secondaryLabel}
</button>
) : null}
</div>
</div>
</>
)
}