Skip to content
Nizivo UI

PageIndicator

Where a carousel, a product's photos or an onboarding sequence is, as dots or as a "2 / 9" chip. The visual is decorative; a visually hidden "2 of 9" tells a screen reader the same.

Server component, no client JS

Import

import { PageIndicator } from '@nizivo/react/page-indicator';

// Once per app (Getting started), after
// @nizivo/tokens/tokens.css and @nizivo/react/css/base.css
import '@nizivo/react/css/page-indicator.css';

Static or interactive

Server. No client JavaScript. It shows a position the page already knows; the carousel or the steps around it own the controls. How to choose.

Dots or fraction

variant="dots" (the default) draws one dot per page, and the current one longer and in the brand colour, so the position does not rest on colour alone. variant="fraction" shows "2 / 9" in a pill, better for more than about seven pages. count is how many there are and current the one shown now, from 1; current is kept between 1 and count.

On a photo

tone="media" is for an indicator over a photo or a video: white dots, and a dark chip with white text. Design has not drawn an on-media colour family yet, so it uses bg/code and text/on-dark, as the storefront patterns do; their contrast holds in light and dark because neither flips.

Screen readers

The dots and the chip are aria-hidden. A visually hidden "2 of 9" says the position instead; labels.position (with {current} and {count}) replaces it, for example labels={{ position: 'Photo {current} of {count}' }}, and locale formats the numbers. It is a server part, so a NizivoConfig's labels do not reach it: pass labels on each instance.

Examples

Basic

Dots under a product's photos, and a "2 / 9" chip for a longer set.

1 of 4
2 of 9
import type { JSX } from 'react';
import { PageIndicator } from '@nizivo/react/page-indicator';

export function PageIndicatorExample(): JSX.Element {
  return (
    <div style={{ display: 'grid', gap: 16, justifyItems: 'start' }}>
      <PageIndicator count={4} current={1} />
      <PageIndicator count={9} current={2} variant="fraction" />
    </div>
  );
}

Media

Over a photo (tone="media"): white dots, and a dark chip with white text.

3 of 4
3 of 4
import type { JSX } from 'react';
import { PageIndicator } from '@nizivo/react/page-indicator';

export function PageIndicatorMediaExample(): JSX.Element {
  return (
    <div
      style={{
        display: 'flex',
        alignItems: 'flex-end',
        justifyContent: 'space-between',
        boxSizing: 'border-box',
        inlineSize: 320,
        blockSize: 200,
        padding: 12,
        borderRadius: 12,
        background: 'linear-gradient(135deg, #c9b79c, #8a6e4b)',
      }}
    >
      <PageIndicator count={4} current={3} tone="media" />
      <PageIndicator count={4} current={3} variant="fraction" tone="media" />
    </div>
  );
}

Props

Server component Renders data-slot="page-indicator" with the class nz-page-indicator. Props: PageIndicatorProps. Source: src/page-indicator/page-indicator.tsx.

NameTypeDefaultDescription
countrequirednumber–

How many pages, slides or photos there are.

currentrequirednumber–

The one shown now, from 1.

labelsPartial<PageIndicatorLabels>–

Overrides the screen-reader position, for example labels={{ position: 'Foto {current} von {count}' }}.

localestring'en-US'

BCP 47 tag for the numbers.

renderRenderProp<Record<string, never>>–

Must render a <div>.

tone"surface" | "media"'surface'

'media' over a photo or video; 'surface' on the page.

variant"dots" | "fraction"'dots'

Dots, one per page, or a "1 / 4" chip for longer sets.

  • Also takes every attribute of <div> except children. (Omit<ComponentPropsWithRef<"div">, "children">)

render takes an element, or, in client code, a function of the props and no state.

Other exports

PageIndicatorLabels type

import type { PageIndicatorLabels } from '@nizivo/react/page-indicator'

PageIndicator's own strings (§16.4): serialisable, English defaults.

NameTypeDefaultDescription
positionrequiredstring'{current} of {count}'

The position, read by a screen reader instead of the visual: {current} and {count}.

PageIndicatorProps type

import type { PageIndicatorProps } from '@nizivo/react/page-indicator'

The props of PageIndicator, listed above.

Data attributes and slots

Style parts by class (.nz-<slot>) and state by data attribute. Attribute meanings come from contracts/vocabulary.json.

SlotRendered byData attributes
page-indicator
.nz-page-indicator
PageIndicator
root (takes render)
  • data-tone: "surface""media" ← tone
    The tone prop; values in each component manifest
  • data-variant: "dots""fraction" ← variant
    The variant prop; values are the lowercase Figma names in each component manifest
page-indicator-dot
.nz-page-indicator-dot
PageIndicator
inner element (CSS only)
  • data-selected (present or absent)
    Selected
page-indicator-dots
.nz-page-indicator-dots
PageIndicator
inner element (CSS only)
none
page-indicator-fraction
.nz-page-indicator-fraction
PageIndicator
inner element (CSS only)
none

CSS hooks

Set a hook on the component's class or any ancestor to restyle it without specificity games; leave it unset for the default shown.

HookDefaultRead as
--nz-page-indicator-chip-bg
  • default: var(--nz-bg-subtle)
  • data-tone="media": var(--nz-bg-code)
  • background on .nz-page-indicator-fraction
--nz-page-indicator-chip-fg
  • default: var(--nz-text-primary)
  • data-tone="media": var(--nz-text-on-dark)
  • color on .nz-page-indicator-fraction
--nz-page-indicator-current
  • default: var(--nz-bg-brand)
  • data-tone="media": var(--nz-text-on-dark)
  • background on .nz-page-indicator-dot[data-selected]
--nz-page-indicator-dot
  • default: var(--nz-border-strong)
  • data-tone="media": color-mix(in srgb, var(--nz-text-on-dark) 50%, transparent)
  • background on .nz-page-indicator-dot

Layers: nz.components. Classes: .nz-page-indicator, .nz-page-indicator-dot, .nz-page-indicator-dots, .nz-page-indicator-fraction.

Tokens this stylesheet reads (15)

--nz-bg-brand, --nz-bg-code, --nz-bg-subtle, --nz-border-strong, --nz-duration-fast, --nz-easing-standard, --nz-font-label-m, --nz-radius-full, --nz-space-0-5, --nz-space-1-5, --nz-space-2, --nz-space-4, --nz-text-on-dark, --nz-text-primary, --nz-tracking-label-m

Accessibility

Nothing in this component takes focus or keyboard input.

Keyboard

None.

Figma

Node ids from design/component-map.json, which nz gen writes from component.json. The links open the Nizivo Figma library, which may ask you to sign in.

  • Canonical: none
  • Ghost masters: none

On this page