Count Indicator
A count indicator shows the current position within a set of items using dots and optional navigation controls.
The Count Indicator (also known as pagination dots or carousel indicators) provides a quick visual cue to show where the user is within a sequence. It communicates:
- Current position (which item is being viewed)
- Total number of items
- Progress through the sequence
It’s commonly used in image carousels, step-by-step flows, or small collections where space is limited and full pagination controls are unnecessary.
When to use it (and when not to)
Section titled “When to use it (and when not to)”Use a Count indicator for:
- Do use it for simple, sequential navigation (e.g., image sliders, onboarding screens).
- Do ensure the current item is clearly distinguished (through color, size, or shape).
- Do keep the number of dots manageable (usually under 10).
- Do provide keyboard and screen-reader support if the dots are interactive.
Avoid using a Count indicator when:
- Don’t use it for large or complex collections (use full pagination or a different pattern instead).
- Don’t rely only on subtle color changes — the active state must be clearly visible.
- Don’t add text content inside the dots (they should remain simple visual indicators).
Properties
Section titled “Properties”Anatomy
Section titled “Anatomy”Position : 1st by Contrast
Section titled “Position : 1st by Contrast”False
color-foreground-neutral-default#333333color-foreground-neutral-default#282830color-fill-neutral-emphasis#000000color-fill-neutral-emphasis#000000color-fill-neutral-subtle#e5e3e1color-fill-neutral-subtle#6c7073Position : Mid by Contrast
Section titled “Position : Mid by Contrast”False
color-foreground-neutral-default#333333color-foreground-neutral-default#282830color-fill-neutral-emphasis#000000color-fill-neutral-emphasis#000000color-fill-neutral-subtle#e5e3e1color-fill-neutral-subtle#6c7073True
color-foreground-contrast-emphasis#ffffffcolor-foreground-contrast-emphasis#ffffffcolor-fill-contrast-emphasis#ffffffcolor-fill-contrast-emphasis#ffffffcolor-fill-contrast-subtle#d4d2d1color-fill-contrast-subtle#a8aaacBoolean properties
Section titled “Boolean properties”Has helper
Has buttons
Has dots
Layout and spacing
Section titled “Layout and spacing”Count indicator
buttons
dots
Styling
Section titled “Styling”Colors
Section titled “Colors”| Name | Applied as | Applied to |
|---|---|---|
color-foreground-neutral-default | Text color | Progress text |
color-foreground-neutral-default | Text color | Progress text |
color-fill-neutral-emphasis | Background color | Progress bar (active dot) |
color-fill-neutral-emphasis | Background color | Progress bar (active dot) |
color-fill-neutral-subtle | Background color | Ellipse (inactive dot) |
color-fill-neutral-subtle | Background color | Ellipse (inactive dot) |
color-foreground-contrast-emphasis | Text color | Progress text (contrast) |
color-foreground-contrast-emphasis | Text color | Progress text (contrast) |
color-fill-contrast-emphasis | Background color | Progress bar (active dot, contrast) |
color-fill-contrast-emphasis | Background color | Progress bar (active dot, contrast) |
color-fill-contrast-subtle | Background color | Ellipse (inactive dot, contrast) |
color-fill-contrast-subtle | Background color | Ellipse (inactive dot, contrast) |
Spacing
Section titled “Spacing”| Name | Applied as | Applied to |
|---|---|---|
spacing-08 | Item spacing / Gap | Dots, Buttons, Count indicator |
spacing-08 | Item spacing / Gap | Dots, Buttons, Count indicator |
spacing-08 | Dot size | Ellipse (inactive dot) |
spacing-08 | Dot size | Ellipse (inactive dot) |
spacing-24 | Inline size | Progress bar (active dot) |
spacing-24 | Inline size | Progress bar (active dot) |
radius-xl | Border radius | Dots |
radius-xl | Border radius | Dots |
Text Styles
Section titled “Text Styles”| Name | Applied as | Applied to |
|---|---|---|
Lorem Ipsum typography-body-8 | Text style | Progress text |
Lorem Ipsum typography-body-8 | Text style | Progress text |
Styles
Section titled “Styles”A count indicator shows the current position within a set of items using dots and optional navigation controls.
<div class="tng-count-indicator"> <div class="tng-count-indicator-helper">1 of 10</div> <div class="tng-count-indicator-dots"> <div class="is-current"></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> </div> <div class="tng-count-indicator-buttons"> <button class="tng-icon-button is-sm" aria-label="Previous"> <i class="tng-icon icon-chevron-left" aria-hidden="true"></i> </button> <button class="tng-icon-button is-sm" aria-label="Next"> <i class="tng-icon icon-chevron-right" aria-hidden="true"></i> </button> </div></div>Import the CountIndicator component from @tmedxp/react-components.
Properties
Section titled “Properties”| Prop | Type | Description | Required |
|---|---|---|---|
total | number | Total number of items. | ✅ |
index | number | Zero-based current item index. | ✅ |
onPrev | () => void | Previous action callback. | ✅ |
onNext | () => void | Next action callback. | ✅ |
wrap | boolean | Loops navigation at boundaries. | |
showHelper | boolean | Show X of Y helper text. Default true. | |
showButtons | boolean | Show previous/next buttons. Default true. | |
showDots | boolean | Show dots indicator. Default true. | |
maxDots | number | Maximum number of rendered dots. Default 10. | |
semanticDots | boolean | Use 1:1 semantic dots when total <= maxDots. Default true. | |
ariaLabel | string | Label for the root group. | ✅ |
ariaLabelDots | string | Label for dots group. | ✅ |
prevAriaLabel | string | Previous button aria-label. | ✅ |
nextAriaLabel | string | Next button aria-label. | ✅ |
helperOfLabel | string | Translation for of in helper text. | ✅ |
className | string | Extra class name for root element. |
Example: default
Section titled “Example: default”import { useState } from 'react';import { CountIndicator } from '@tmedxp/react-components';
const CountIndicatorDefaultExample = () => { const total = 10; const [index, setIndex] = useState(0);
return ( <CountIndicator total={total} index={index} ariaLabel="count indicator" ariaLabelDots="progress" prevAriaLabel="previous" nextAriaLabel="next" helperOfLabel="of" onPrev={() => setIndex((i) => Math.max(0, i - 1))} onNext={() => setIndex((i) => Math.min(total - 1, i + 1))} /> );};
export { CountIndicatorDefaultExample };Example: helper and dots only
Section titled “Example: helper and dots only”import { CountIndicator } from '@tmedxp/react-components';
const CountIndicatorSimpleExample = () => { return ( <CountIndicator total={42} index={5} onPrev={() => {}} onNext={() => {}} showButtons={false} maxDots={5} ariaLabel="count indicator" ariaLabelDots="progress" prevAriaLabel="previous" nextAriaLabel="next" helperOfLabel="of" /> );};
export { CountIndicatorSimpleExample };For designers
Section titled “For designers”- All states (current dot, non-current dot, button hover, button focus, button disabled) must maintain accessible contrast in both light and dark background contexts.
- Focus styles must remain visible and meet WCAG AA contrast requirements across all supported surfaces.
- The current dot and disabled buttons must use more than colour alone to convey state — pair with shape, position, or supporting helper text.
- Colour tokens used within the component should be semantic (e.g.
color-foreground-neutral-default) rather than fixed values. This ensures the component adapts correctly to different themes or surfaces.
For developers
Section titled “For developers”The following are general recommendations. The exact approach depends widely on your use-case.
Wrapper
Section titled “Wrapper”The count indicator is a set of navigation controls — it is not a carousel. It can be used in two contexts:
- Inside a carousel or gallery — In this case,
role="group" aria-roledescription="carousel"andaria-labelbelong on the outer content container (the element wrapping both the slides and these controls), not ontng-count-indicatoritself. - Standalone pagination — When paginating a list or search results, use a
<nav>element or addrole="navigation"so screen readers expose it as a navigation landmark.
<nav class="tng-count-indicator" aria-label="Search results pages">…</nav>If a landmark is not appropriate (e.g. the controls are already inside a labelled region), role="group" with an aria-label is a lighter alternative.
<div class="tng-count-indicator" role="group" aria-label="Gallery navigation"> …</div>Helper text
Section titled “Helper text”Add aria-live="polite" to tng-count-indicator-helper so screen readers announce changes as the user navigates.
<div class="tng-count-indicator-helper" aria-live="polite">1 of 42</div>The dots serve as a visual progress indicator. Depending on whether they are an accurate or approximate representation of the item count, choose one of the following patterns.
Decorative dots
Section titled “Decorative dots”When the dot count does not match the actual item count (e.g. a maximum of 10 dots is shown for 42 items), the dots are purely decorative. Add aria-hidden="true" to tng-count-indicator-dots — the helper text already conveys the current state.
<div class="tng-count-indicator-dots" aria-hidden="true"> <div class="is-current"></div> <div></div> <div></div></div>Semantic dots
Section titled “Semantic dots”When each dot maps 1:1 to an actual item, give the dots semantic meaning. Add role="group" and an aria-label to tng-count-indicator-dots. Mark each dot with an aria-label describing its position and use aria-current="step" instead of (or alongside) is-current to indicate the active item. The styles already support this — aria-current is handled alongside is-current.
<div class="tng-count-indicator-dots" role="group" aria-label="Progress"> <div aria-current="step" aria-label="Item 1 of 5"></div> <div aria-label="Item 2 of 5"></div> <div aria-label="Item 3 of 5"></div> <div aria-label="Item 4 of 5"></div> <div aria-label="Item 5 of 5"></div></div>Navigation buttons
Section titled “Navigation buttons”Use aria-label on the buttons themselves (e.g. "Previous item", "Next item").
<div class="tng-count-indicator-buttons"> <button class="tng-icon-button is-sm" aria-label="Previous item"> <i class="tng-icon icon-chevron-left" aria-hidden="true"></i> </button> <button class="tng-icon-button is-sm" aria-label="Next item"> <i class="tng-icon icon-chevron-right" aria-hidden="true"></i> </button></div>