Accordion

Timeline Accordion

A timeline accordion: a line with dots on the left, expandable entries on the right. That is how a changelog is read — by date first, then into one entry.

  • accordion
  • timeline
  • changelog
  • history

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/accordion-009?lang=en

12 мартаРелизПанель кода в карточке каталога

Код компонента открывается прямо на витрине: команда установки, исходник и копирование — без перехода на страницу item'а.

4 мартаBetaНастройка компонента перед выдачей агенту

Подписи, размеры и акцент меняются на карточке, значения уезжают в ссылку. Исходник при этом не трогается.

27 февраляАнглийская версия каталога

Интерфейс, метаданные и инструкция для агента переведены целиком. Русский остаётся основным, английский живёт под /en.

19 февраляИсправлениеМиниатюры перестали показывать мобильную вёрстку

Раскладка блоков считается от собственной ширины через container-запросы, поэтому в карточке виден настоящий десктопный дизайн.

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 "accordion-009" (Timeline Accordion) 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/accordion-009.json

Registry item: https://vibeui.ru/r/accordion-009.json
Installs to: components/vibeui/accordion-009.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 timeline accordion: a line with dots on the left, expandable entries on the right. That is how a changelog is read — by date first, then into one entry.

A timeline of expandable entries: a continuous line on the left, a dot per entry, the date and a release tag in the heading row. The top entry's dot is filled with the accent and the line stops at the last one. Zero dependencies, one file, its own palette, no client JS.

## 3. How to use it
import { Accordion009 } from "@/components/vibeui/accordion-009"

<Accordion009
  entries={[{ date: "12 March", tag: "Release", title: "Code panel", body: "The code opens right on the catalog card." }]}
/>

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-accordion-009-* palette — do not swap it for your theme tokens (border-border, text-muted-foreground and the like)
- the line and dots as pseudo-elements of the entries: separate elements drift apart when a row wraps
- stopping the line at the last entry — a line running into empty space reads as an unloaded list
- the filled dot on the first entry: in a timeline the newest event matters most
- the native details/summary instead of stateful buttons
- tabular-nums on the date: without them the date column jitters
- the @container query that moves the date into its own column on the wide layout
- the <style> block inside the component — it holds the palette, the line and the dots

## 6. You may change
- the entries array: date, tag, title and body
- defaultOpen — which entry starts open; -1 closes them all
- the accent through the accent prop — it colours the dot, the tag and hover
- max width and outer spacing through className

## 7. Rules
- Entries run newest first: the accent dot sits on the first one, so do not reverse the order.
- The date arrives as a string: formatting belongs to the caller, the component parses no Date and knows no locale.
- For a long history group by year outside the component rather than growing one list to a hundred entries.
- 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/accordion-009.json
https://vibeui.ru/r/accordion-009.json

Компонент самодостаточен: один файл, без зависимостей, собственная палитра в локальных переменных --vibeui-accordion-009-*. Линия ленты и точка — псевдоэлементы каждой записи, поэтому лишних элементов в разметке нет; у последней записи линия обрывается на её точке. Точка первой записи залита акцентом: свежее событие важнее остальных. От 34rem собственной ширины дата уходит в отдельную колонку слева от заголовка.

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 Accordion009Entry = {
  date: string
  title: string
  body: string
  /** Метка выпуска: «Релиз», «Исправление», «Beta». */
  tag?: string
}

export type Accordion009Props = Omit<
  ComponentPropsWithoutRef<"div">,
  "children"
> & {
  entries?: Accordion009Entry[]
  defaultOpen?: number
  accent?: string
}

// Идея компонента: аккордеон-лента событий. Слева непрерывная линия с точками,
// справа раскрывающиеся записи — так читают историю изменений: сначала по
// датам, потом вглубь одной записи. Точка верхней записи залита акцентом:
// последнее событие важнее остальных, и оно должно быть видно сразу.
const STYLES = `
:where([data-vibeui-block="accordion-009"]){
--vibeui-accordion-009-fg:oklch(0.22 0.014 265);
--vibeui-accordion-009-muted:oklch(0.52 0.014 265);
--vibeui-accordion-009-bg:oklch(1 0 0);
--vibeui-accordion-009-line:oklch(0.9 0.006 265);
--vibeui-accordion-009-accent:oklch(0.55 0.2 262);
--vibeui-accordion-009-font:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
container-type:inline-size;
}
[data-vibeui-block="accordion-009"]{
display:flex;flex-direction:column;
width:100%;max-width:40rem;box-sizing:border-box;
color:var(--vibeui-accordion-009-fg);font-family:var(--vibeui-accordion-009-font);
}
[data-vibeui-block="accordion-009"] details{position:relative;padding-left:1.75rem}
/* Линия ленты: у последней записи она обрывается на её точке. */
[data-vibeui-block="accordion-009"] details::before{
content:"";position:absolute;left:0.3125rem;top:0;bottom:0;
width:1px;background:var(--vibeui-accordion-009-line);
}
[data-vibeui-block="accordion-009"] details:last-child::before{bottom:auto;height:1.125rem}
[data-vibeui-block="accordion-009"] details::after{
content:"";position:absolute;left:0;top:0.875rem;
width:0.6875rem;height:0.6875rem;border-radius:9999px;
border:2px solid var(--vibeui-accordion-009-line);
background:var(--vibeui-accordion-009-bg);
}
[data-vibeui-block="accordion-009"] details:first-child::after{
border-color:var(--vibeui-accordion-009-accent);
background:var(--vibeui-accordion-009-accent);
}
[data-vibeui-block="accordion-009"] details[open]::after{border-color:var(--vibeui-accordion-009-accent)}
[data-vibeui-block="accordion-009"] summary{
display:flex;align-items:baseline;gap:0.625rem;flex-wrap:wrap;
padding:0.625rem 0 0.75rem;cursor:pointer;list-style:none;
}
[data-vibeui-block="accordion-009"] summary::-webkit-details-marker{display:none}
[data-vibeui-block="accordion-009"] summary:focus-visible{outline:2px solid var(--vibeui-accordion-009-accent);outline-offset:2px;border-radius:0.375rem}
[data-vibeui-block="accordion-009"] [data-part="date"]{
flex:none;font-size:0.75rem;color:var(--vibeui-accordion-009-muted);
font-variant-numeric:tabular-nums;
}
[data-vibeui-block="accordion-009"] [data-part="tag"]{
flex:none;padding:0.0625rem 0.375rem;border-radius:0.3125rem;
background:color-mix(in oklab,var(--vibeui-accordion-009-accent) 12%,transparent);
color:var(--vibeui-accordion-009-accent);
font-size:0.6875rem;font-weight:600;
}
[data-vibeui-block="accordion-009"] [data-part="title"]{
flex:1 1 100%;font-size:0.9375rem;font-weight:550;line-height:1.4;
transition:color .16s ease;
}
[data-vibeui-block="accordion-009"] summary:hover [data-part="title"]{color:var(--vibeui-accordion-009-accent)}
[data-vibeui-block="accordion-009"] [data-part="body"]{
margin:0;padding:0 0 1rem;
font-size:0.875rem;line-height:1.6;color:var(--vibeui-accordion-009-muted);max-width:58ch;
}
@container (min-width: 34rem){
[data-vibeui-block="accordion-009"] summary{flex-wrap:nowrap}
[data-vibeui-block="accordion-009"] [data-part="date"]{width:5.5rem}
[data-vibeui-block="accordion-009"] [data-part="title"]{flex:1 1 auto}
}
@media (prefers-reduced-motion:reduce){[data-vibeui-block="accordion-009"] *{animation:none!important;transition:none!important}}
`

const DEFAULT_ENTRIES: Accordion009Entry[] = [
  {
    date: "12 марта",
    tag: "Релиз",
    title: "Панель кода в карточке каталога",
    body: "Код компонента открывается прямо на витрине: команда установки, исходник и копирование — без перехода на страницу item'а.",
  },
  {
    date: "4 марта",
    tag: "Beta",
    title: "Настройка компонента перед выдачей агенту",
    body: "Подписи, размеры и акцент меняются на карточке, значения уезжают в ссылку. Исходник при этом не трогается.",
  },
  {
    date: "27 февраля",
    title: "Английская версия каталога",
    body: "Интерфейс, метаданные и инструкция для агента переведены целиком. Русский остаётся основным, английский живёт под /en.",
  },
  {
    date: "19 февраля",
    tag: "Исправление",
    title: "Миниатюры перестали показывать мобильную вёрстку",
    body: "Раскладка блоков считается от собственной ширины через container-запросы, поэтому в карточке виден настоящий десктопный дизайн.",
  },
]

/**
 * Аккордеон-лента событий: линия с точками и раскрывающиеся записи.
 * Один файл, ноль зависимостей, собственная палитра.
 */
export function Accordion009({
  entries = DEFAULT_ENTRIES,
  defaultOpen = 0,
  accent,
  className,
  style,
  ...props
}: Accordion009Props) {
  const palette = {
    ...(accent ? { "--vibeui-accordion-009-accent": accent } : null),
    ...style,
  } as CSSProperties

  return (
    <>
      <style href="vibeui-accordion-009" precedence="medium">
        {STYLES}
      </style>
      <div
        {...props}
        data-vibeui-block="accordion-009"
        className={className}
        style={palette}
      >
        {entries.map((entry, index) => (
          <details key={entry.title} open={index === defaultOpen}>
            <summary>
              <span data-part="date">{entry.date}</span>
              {entry.tag ? <span data-part="tag">{entry.tag}</span> : null}
              <span data-part="title">{entry.title}</span>
            </summary>
            <p data-part="body">{entry.body}</p>
          </details>
        ))}
      </div>
    </>
  )
}