Skip to content

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

Vennligst vent ...
<ProgressIndicator
  // label="Custom label ..."
  type="circular"
  showDefaultLabel={true}
  labelDirection="horizontal"
/>
Vennligst vent ...
<ProgressIndicator
  type="linear"
  // label="Custom label ..."
  showDefaultLabel={true}
  labelDirection="horizontal"
/>

Vertical label

The default label direction is vertical.

Vennligst vent ...
<ProgressIndicator
  // label="Custom label ..."
  type="circular"
  showDefaultLabel={true}
/>
Vennligst vent ...
<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.

72%
<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.

20 dleft
done