Skip to content

Progress

A slim bar that fills as a task completes — uploads, installs, multi-step onboarding — with the neobrutalist borders-and-shadows treatment.

"use client"

import * as React from "react"

The progress bar reports how much of a task is done — a track that fills from 0 to 100. Built on the Base UI Progress component and styled to the neobrutalist recipe: thick border, hard shadow, solid fill.

Reach for it when:

  • File uploads and downloads — determinate, byte-driven progress with a visible percentage.
  • Multi-step flows — onboarding, checkout, and wizards; the bar shows how far along the user is.
  • Long-running jobs — imports, exports, and installs that report completion from the server.

Installation

pnpm dlx shadcn@latest add https://neobrutalism.com/r/base/progress.json
npx shadcn@latest add https://neobrutalism.com/r/base/progress.json
yarn dlx shadcn@latest add https://neobrutalism.com/r/base/progress.json
bunx --bun shadcn@latest add https://neobrutalism.com/r/base/progress.json

Install the following dependencies:

pnpm add @base-ui/react
npm install @base-ui/react
yarn add @base-ui/react
bun add @base-ui/react

Copy and paste the following code into your project.

components/ui/progress.tsx
"use client"

import * as React from "react"
import { Progress as ProgressPrimitive } from "radix-ui"

import { cn } from "@/lib/utils"

function Progress({
  className,
  value,
  ...props
}: React.ComponentProps<typeof ProgressPrimitive.Root>) {
  return (
    <ProgressPrimitive.Root
      data-slot="progress"
      className={cn(
        "relative flex h-4 w-full items-center overflow-hidden rounded border-2 bg-background",
        className
      )}
      {...props}
    >
      <ProgressPrimitive.Indicator
        data-slot="progress-indicator"
        className="size-full flex-1 bg-primary transition-all"
        style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
      />
    </ProgressPrimitive.Root>
  )
}

export { Progress }

Update the import paths to match your project setup.

Usage

import { Progress } from "@/components/ui/progress"
<Progress value={33} />

Composition

With label and value

Use ProgressLabel and ProgressValue to add a label and value display.

import {
  Progress,
  ProgressLabel,
  ProgressValue,
} from "@/components/ui/progress"
 
;<Progress value={56} className="w-full max-w-sm">
  <ProgressLabel>Upload progress</ProgressLabel>
  <ProgressValue />
</Progress>
Progress
├── ProgressLabel
├── ProgressValue
└── ProgressTrack
    └── ProgressIndicator

Examples

Label

Use ProgressLabel and ProgressValue to add a label and value display.

import {
  Progress,
  ProgressLabel,

Controlled

A progress bar that can be controlled by a slider.

"use client"

import * as React from "react"

RTL

To enable RTL support in Neobrutalism.com, see the RTL configuration guide.

"use client"

import * as React from "react"

Accessibility

Progress is a status indicator, not a control — it never takes focus and has no keyboard interactions. Base UI renders role="progressbar" with aria-valuemin, aria-valuemax, and aria-valuenow, and ProgressLabel is associated automatically via aria-labelledby — prefer it (or an aria-label) over an unlabeled bar so screen readers can say what is loading, not just the percentage. Pass value={null} when completion is unknown; the bar switches to an indeterminate state.

API Reference

See the Base UI Progress documentation.