Display

Named Step Progress

Progress that gives its main answer in words: a large line names the current step and the one after it, while the milestones on a continuous track act as a map of the route.

  • progress
  • steps
  • wizard
  • display

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/progress-008?lang=en

Catalogue import · шаг 3 из 5

Проверка данных

Дальше: Сопоставление полей

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 "progress-008" (Named Step Progress) 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/progress-008.json

Registry item: https://vibeui.ru/r/progress-008.json
Installs to: components/vibeui/progress-008.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
Progress that gives its main answer in words: a large line names the current step and the one after it, while the milestones on a continuous track act as a map of the route.

Step progress: the current step is named in words by a large line, and milestones on a continuous track show how much is left. Zero dependencies, one file, server rendered.

## 3. How to use it
import { Progress008 } from "@/components/vibeui/progress-008"

<Progress008
  title="Catalogue import"
  steps={["Upload file", "Parse columns", "Validate data"]}
  current={2}
/>

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-progress-008-* palette — do not swap it for your theme tokens
- the large line with the step name: it is the main answer, the ratio is secondary
- the index / (total − 1) formula: dividing by total leaves the fill short of the last milestone
- the surface-coloured ring around each milestone — without it the line shows through the dot
- the aria-valuetext repeating the caption in words: "3 of 5" says nothing about the step itself
- the card's own light surface: without it the dark text disappears on a dark background

## 6. You may change
- the step list through steps
- the current step through current
- the process heading through title
- the fill and milestone colour through the accent variable

## 7. Rules
- A single step in steps fills the whole track: that is deliberate, not a division by zero.
- Step names are not truncated: a very long one wraps to a second line and pushes the milestones down.
- The component deliberately draws no captions under the milestones — the large line takes that role.
- 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/progress-008.json
https://vibeui.ru/r/progress-008.json

Компонент самодостаточен: один файл, без зависимостей, собственная палитра в локальных переменных --vibeui-progress-008-*. Серверный: хуков нет. Дорожка нарисована двумя псевдоэлементами контейнера: ::before — серая линия на всю ширину, ::after — заливка до текущей вехи по переменной значения; вехи лежат поверх обычными span'ами в flex с распором. Кольцо цвета подложки у вехи задано border, поэтому линия под ней не просвечивает. Доля считается как index / (total − 1): заливка приходит ровно в центр текущей вехи, а не «примерно туда». role="progressbar" объявлен в шагах, aria-valuetext повторяет строку «Шаг 3 из 5: Проверка данных».

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 Progress008Props = Omit<
  ComponentPropsWithoutRef<"div">,
  "children"
> & {
  steps?: string[]
  current?: number
  title?: string
}

// Идея компонента: главный ответ здесь — словами, а не долей. Крупная строка
// называет текущий шаг и следующий за ним, а вехи на непрерывной дорожке
// служат только картой пути. Дорожка одна, заливка идёт до текущей вехи:
// расстояние между вехами показывает, сколько ещё впереди.
const STYLES = `
:where([data-vibeui-block="progress-008"]){
--vibeui-progress-008-bg:oklch(1 0 0);
--vibeui-progress-008-fg:oklch(0.24 0.016 265);
--vibeui-progress-008-muted:oklch(0.56 0.014 265);
--vibeui-progress-008-border:oklch(0.9 0.006 265);
--vibeui-progress-008-track:oklch(0.92 0.006 265);
--vibeui-progress-008-accent:oklch(0.55 0.19 262);
--vibeui-progress-008-value:0;
--vibeui-progress-008-font:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
}
[data-vibeui-block="progress-008"]{
display:flex;flex-direction:column;gap:0.875rem;
width:100%;max-width:26rem;box-sizing:border-box;padding:1.125rem 1.25rem;
background:var(--vibeui-progress-008-bg);
border:1px solid var(--vibeui-progress-008-border);border-radius:1rem;
font-family:var(--vibeui-progress-008-font);color:var(--vibeui-progress-008-fg);
}
[data-vibeui-block="progress-008"] [data-part="eyebrow"]{
font-size:0.6875rem;font-weight:700;letter-spacing:0.06em;text-transform:uppercase;
color:var(--vibeui-progress-008-muted);font-variant-numeric:tabular-nums;
}
/* Текущий шаг словами: это главный ответ, поэтому он крупнее всего блока. */
[data-vibeui-block="progress-008"] [data-part="now"]{
margin:0;font-size:1.0625rem;font-weight:700;line-height:1.2;letter-spacing:-0.01em;
}
[data-vibeui-block="progress-008"] [data-part="next"]{
margin:0;font-size:0.75rem;color:var(--vibeui-progress-008-muted);
}
/* Одна дорожка с вехами: расстояние между точками показывает остаток пути. */
[data-vibeui-block="progress-008"] [data-part="track"]{
position:relative;display:flex;align-items:center;justify-content:space-between;
height:0.875rem;
}
[data-vibeui-block="progress-008"] [data-part="track"]::before,
[data-vibeui-block="progress-008"] [data-part="track"]::after{
content:"";position:absolute;left:0;top:50%;
height:0.25rem;margin-top:-0.125rem;border-radius:9999px;
}
[data-vibeui-block="progress-008"] [data-part="track"]::before{
right:0;background:var(--vibeui-progress-008-track);
}
[data-vibeui-block="progress-008"] [data-part="track"]::after{
width:calc(var(--vibeui-progress-008-value) * 1%);
background:var(--vibeui-progress-008-accent);
transition:width .35s cubic-bezier(.32,.72,0,1);
}
[data-vibeui-block="progress-008"] [data-part="pin"]{
position:relative;z-index:1;
width:0.875rem;height:0.875rem;border-radius:9999px;
box-sizing:border-box;border:0.1875rem solid var(--vibeui-progress-008-bg);
background:var(--vibeui-progress-008-track);
}
[data-vibeui-block="progress-008"] [data-part="pin"][data-state="done"]{background:var(--vibeui-progress-008-accent)}
[data-vibeui-block="progress-008"] [data-part="pin"][data-state="current"]{
background:var(--vibeui-progress-008-accent);
outline:2px solid color-mix(in oklch,var(--vibeui-progress-008-accent) 40%,transparent);
outline-offset:1px;
}
@media (prefers-reduced-motion:reduce){
[data-vibeui-block="progress-008"] *{animation:none!important;transition:none!important}
}
`

const DEFAULT_STEPS = [
  "Загрузка файла",
  "Разбор колонок",
  "Проверка данных",
  "Сопоставление полей",
  "Импорт",
]

/**
 * Прогресс, где текущий шаг назван словами, а вехи — карта пути.
 * Один файл, ноль зависимостей, собственная палитра.
 */
export function Progress008({
  steps = DEFAULT_STEPS,
  current = 2,
  title = "Импорт справочника",
  className,
  style,
  ...props
}: Progress008Props) {
  const total = steps.length
  const index = Math.min(Math.max(0, current), total - 1)
  const percent = total > 1 ? (index / (total - 1)) * 100 : 100
  const next = steps[index + 1]
  const palette = {
    "--vibeui-progress-008-value": percent,
    ...style,
  } as CSSProperties

  return (
    <>
      <style href="vibeui-progress-008" precedence="medium">
        {STYLES}
      </style>
      <div
        {...props}
        data-vibeui-block="progress-008"
        className={className}
        style={palette}
      >
        <span data-part="eyebrow">
          {title} · шаг {index + 1} из {total}
        </span>
        <p data-part="now">{steps[index]}</p>
        <div
          data-part="track"
          role="progressbar"
          aria-label={title}
          aria-valuemin={1}
          aria-valuemax={total}
          aria-valuenow={index + 1}
          aria-valuetext={`Шаг ${index + 1} из ${total}: ${steps[index]}`}
        >
          {steps.map((step, position) => (
            <span
              key={step}
              data-part="pin"
              data-state={
                position < index
                  ? "done"
                  : position === index
                    ? "current"
                    : "todo"
              }
              title={step}
            />
          ))}
        </div>
        <p data-part="next">{next ? `Дальше: ${next}` : "Это последний шаг"}</p>
      </div>
    </>
  )
}