Progress
Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.
import { css, type Handle } from 'remix/component'
import { Progress } from '#app/ui/progress.tsx'
export function ProgressDemo(handle: Handle) {
let progress = 13import { css, type Handle } from 'remix/component'
import { Progress } from '#app/ui/progress.tsx'
export function ProgressDemo(handle: Handle) {
let progress = 13
handle.queueTask(() => {
let timer = setTimeout(() => {
progress = 66
void handle.update()
}, 500)
handle.signal.addEventListener('abort', () => clearTimeout(timer))
})
return () => <Progress value={progress} mix={css({ width: '60%' })} />
}Installation
$ bunx --bun shadcn@latest add https://www.shadcn-remix.com/r/progress.json$ npx shadcn@latest add https://www.shadcn-remix.com/r/progress.json$ pnpm dlx shadcn@latest add https://www.shadcn-remix.com/r/progress.json$ yarn dlx shadcn@latest add https://www.shadcn-remix.com/r/progress.jsonInstall the following dependencies:
$ bun add remix$ npm install remix$ pnpm add remix$ yarn add remixCopy and paste the following code into your project.
import { css, type Handle, type Props } from 'remix/component'
export interface ProgressProps extends Props<'div'> {
/** Progress value between 0 and `max`. `null`/omitted renders an indeterminate progress bar. */
value?: number | null
/** Maximum value. Defaults to `100`. */
max?: number
/** Accessible value text. Defaults to the rounded percentage, e.g. `"66%"`. */
getValueLabel?: (value: number, max: number) => string
}
const rootStyles = css({
position: 'relative',
height: '0.5rem',
width: '100%',
overflow: 'hidden',
borderRadius: '9999px',
backgroundColor: 'color-mix(in oklab, var(--primary) 20%, transparent)',
})
const indicatorStyles = css({
height: '100%',
width: '100%',
flex: '1 1 0%',
backgroundColor: 'var(--primary)',
transitionProperty: 'all',
transitionTimingFunction: 'cubic-bezier(0.4, 0, 0.2, 1)',
transitionDuration: '150ms',
})
export function Progress(handle: Handle<ProgressProps>) {
return () => {
let { value, max = 100, getValueLabel, mix, ...props } = handle.props
let current = value == null ? null : Math.min(Math.max(value, 0), max)
let state = current == null ? 'indeterminate' : current === max ? 'complete' : 'loading'
let valueText =
current == null
? undefined
: getValueLabel
? getValueLabel(current, max)
: `${Math.round((current / max) * 100)}%`
return (
<div
data-slot="progress"
role="progressbar"
aria-valuemax={max}
aria-valuemin={0}
aria-valuenow={current ?? undefined}
aria-valuetext={valueText}
data-state={state}
data-value={current ?? undefined}
data-max={max}
{...props}
mix={[rootStyles, mix]}
>
<div
data-slot="progress-indicator"
data-state={state}
data-value={current ?? undefined}
data-max={max}
mix={indicatorStyles}
style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
/>
</div>
)
}
}Update the import paths to match your project setup.
Usage
import { Progress } from '#app/ui/progress.tsx'<Progress value={33} />API Reference
Progress
A role="progressbar" track with an indicator.
| Prop | Type | Default |
|---|---|---|
value | number | null | - |
max | number | 100 |
getValueLabel | (value: number, max: number) => string | - |
mix | MixValue | - |