Demos
Indeterminate (unknown progress)
When the duration is unknown, omit the progress prop to show a continuous animation. The default type is circular.
<ProgressIndicator />
The linear type works well for wider layouts, such as the top of a page or section.
<ProgressIndicator type="linear" />
Determinate (known progress)
Set the progress prop (0–100) when you know how far along the process is. This gives the user a clear expectation of remaining time.
<ProgressIndicator type="circular" progress="50" size="large" noAnimation />
<ProgressIndicator type="linear" progress="50" size="large" noAnimation />
Labels
Labels help users understand what is loading. Use showDefaultLabel for the built-in "In progress..." text, or provide a custom label.
Horizontal label
<ProgressIndicator // label="Custom label ..." type="circular" showDefaultLabel={true} labelDirection="horizontal" />
<ProgressIndicator type="linear" // label="Custom label ..." showDefaultLabel={true} labelDirection="horizontal" />
Vertical label
The default label direction is vertical.
<ProgressIndicator // label="Custom label ..." type="circular" showDefaultLabel={true} />
<ProgressIndicator type="linear" showDefaultLabel={true} />
Inside label (circular only)
Inside labels are placed in the center of the circle. Use sparingly — they work best for short content like an icon or a number.
<ProgressIndicator right label={<IconPrimary icon="save" />} type="circular" labelDirection="inside" /> <ProgressIndicator progress={72} size="large" type="circular" labelDirection="inside" label={ <span className="dnb-p dnb-t__weight--bold dnb-t__size--small"> {72}% </span> } />
Animated progress transitions
When the progress value changes, the indicator animates smoothly between values.
const Example = () => { const random = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min const [progress, setProgressIndicator] = useState(random(1, 100)) useEffect(() => { const timer = setInterval( () => setProgressIndicator(random(1, 100)), 1e3 ) return () => clearInterval(timer) }) return ( <ProgressIndicator type="circular" size="large" progress={progress} /> ) } render(<Example />)
const Example = () => { const random = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min const [progress, setProgressIndicator] = useState(random(1, 100)) useEffect(() => { const timer = setInterval( () => setProgressIndicator(random(1, 100)), 1e3 ) return () => clearInterval(timer) }) return <ProgressIndicator type="linear" progress={progress} /> } render(<Example />)
Controlling visibility with show
Use the show prop to toggle the indicator. The onComplete callback fires after the exit animation finishes, which is useful for sequencing UI updates.
const Example = () => { const random = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min const [show, setShow] = useState(true) useEffect(() => { const timer = setInterval(() => setShow(!show), random(2400, 4200)) return () => clearTimeout(timer) }) return ( <ProgressIndicator type="circular" size="large" show={show} onComplete={() => { console.log('onCompleteCircular') }} /> ) } render(<Example />)
Inside a Dialog
A ProgressIndicator can be placed inside a Dialog to block interaction while a process completes.
<Dialog spacing={false} maxWidth="12rem" fullscreen={false} alignContent="centered" hideCloseButton triggerAttributes={{ text: 'Show', }} preventClose={false} > <ProgressIndicator type="circular" showDefaultLabel top="large" bottom="large" size="large" /> </Dialog>
Countdown
The countdown type animates counterclockwise and is suited for timers, session expiry, or time-limited actions. Combine it with labelDirection="inside" to display a value in the center.
const ChangeValue = () => { const max = 60 const [current, setCurrent] = useState(10) useEffect(() => { const timer = setInterval(() => { setCurrent(current === 0 ? max - 1 : current - 1) }, 1000) return () => clearTimeout(timer) }) return ( <ProgressIndicator type="countdown" progress={(current / max) * 100} title={`${current} av ${max}`} size="large" labelDirection="inside" label={<MyCustomLabel aria-hidden>{current}</MyCustomLabel>} /> ) } render(<ChangeValue />)
Style customization
The sizes and colors can be customized with the properties size, customColors, and customCircleWidth if needed. The types circular and countdown have a few more options than linear.