Skip to main content

Counter

import { Counter } from '@enmovil/ui-design-system';

Shows a row of KPI counters that count up to their value, with optional breakdowns, abbreviation (K/L/Cr or K/M/B), selection and drag-to-reorder.

Properties​

PropertyTypeRequiredDefaultAllowed valuesDescription
kpisKPI[]Yes——The KPIs to display, in order. See the KPI type below.
numberFormatLocalestringNo'en-IN''en-IN', 'en-US', 'en-GB'Locale used to group digits in full values, for example en-IN gives 15,00,000.
enableCaretbooleanNotrue—Shows the caret indicator on the selected KPI in the default variant.
draggablebooleanNofalse—Older way to select the draggable variant. Used only when variant is not set.
variantstringNo—'draggable', 'default', 'card'Selects the counter variant. 'default' = caret style, 'draggable' = drag-and-drop carousel, 'card' = KPI cards. When omitted the component falls back to draggable prop for backward compatibility.
cardWidthstring | numberNo200—Width of each counter card, as a number of pixels or a CSS length.
cardHeightstring | numberNo100—Height of each counter card, as a number of pixels or a CSS length; defaults to 100. In the default variant it is a fixed height, but becomes a minimum height when any KPI has sub-counters, so the cards grow to fit them and stay equal.
activeKpistring | nullNonull—Controlled active key. May be a KPI's key or, once a sub-counter has been clicked, that sub-counter's resolved key — see onActiveKPIChange.
setActiveKpiDispatch<SetStateAction<string | null>>No() => {}—Receives the newly active key. Given a sub-counter's key when one is clicked.
abbreviateCountUpbooleanNofalse—Abbreviates every value (for example 1.5M) and shows the full value in a tooltip. A KPI's own abbreviate overrides this.
cardsPerRownumberNo8—Number of cards per row in the 'card' variant. Additional cards wrap to the next row. Default is 8.
enableSubCounterClickbooleanNofalse—Makes sub-counters individually interactive. Default is false, where a sub-counter is display-only: no pointer cursor, no hover, no selected state, and its onClick never fires. A click then falls through to the KPI around it, exactly as if the sub-counter were not there.

When true, clicking a sub-counter fires its own onClick, suppresses the parent's, highlights both it and its parent, and reports the sub-counter's key through onActiveKPIChange / setActiveKpi.
abbreviationFormatstringNo'international''international', 'indian'Scale used when abbreviating values. 'international' uses K/M/B; 'indian' uses K/L/Cr (lakhs/crores). Default is 'international'.
abbreviationDecimalsnumberNo2—Maximum number of decimal places shown on abbreviated values. Trailing zeros are trimmed. Default is 2.
abbreviationUnitstringNo—'K', 'L', 'Cr', 'M', 'B'Forces every KPI's value into a fixed unit (K/L/Cr/M/B) regardless of magnitude — e.g. a value of 2L renders as "200K", 4Cr as "400L". Works with both formats. Per-KPI abbreviationUnit overrides this.
valueDecimalsnumberNo0—Number of decimal places shown on the full (non-abbreviated) value. Default is 0 (rounded to integers).

kpis​

An array of objects (KPI). Each object has these fields:

FieldTypeRequiredDescription
keystringYesIdentifies the KPI for selection and is passed to its onClick and the selection callbacks. Must be unique, since it is also the React key and the drag id.
titlestringYesLabel shown above the value, or in the card header in the card variant.
subCountersKPISubCounter[]NoBreakdowns rendered under the headline value. Rendered by the 'default' and 'card' variants; the 'draggable' variant ignores them.
valuenumberYesThe number the counter counts up to. The count-up takes 4 seconds for values of 100,000 or more and 1 second otherwise.
iconReact.ReactNodeNoIcon shown beside the value, or at the right of the card header in the card variant. The default and draggable variants leave an empty space when it is absent.
colorstringNoColour of the value (and of the icon in the default variant). In the card variant it also tints the card's highlight; without it a default colour is used.
isCurrencybooleanNoPuts a currency symbol before the value, after any prefix. The symbol is ₹ when numberFormatLocale is en-IN and $ otherwise.
onClick(key: string) => voidNoCalled with the KPI's key when the KPI is clicked, unless it is disabled. Not called in the draggable variant.
disabledbooleanNoIgnores clicks and hover callbacks on the KPI and never shows it as selected. A disabled KPI can still be dragged in the draggable variant.
badgeKPIBadgeNoBadge displayed alongside the title in the 'card' variant.
subtextstringNoSubtext displayed next to the count in the 'card' variant.
prefixstringNoText displayed before the value (e.g. a currency symbol or label).
suffixstringNoText displayed after the value (e.g. a unit like "kg" or "%").
abbreviationFormatAbbreviationFormatNoOverrides the component-level abbreviationFormat for this entry only.
abbreviationUnitAbbreviationUnitNoForces this entry's value into a fixed unit (e.g. show 2L as "200K", 4Cr as "400L"), overriding the auto-scale. Overrides the component-level abbreviationUnit.
abbreviationDecimalsnumberNoOverrides the component-level abbreviationDecimals for this entry only.
valueDecimalsnumberNoOverrides the component-level valueDecimals for this entry only.
abbreviatebooleanNoOverrides the component-level abbreviateCountUp for this entry only. Set true to abbreviate just this entry (or false to keep it full) while the rest follow the component default.

kpis.subCounters​

An array of objects (KPISubCounter). Each object has these fields:

FieldTypeRequiredDescription
keystringNoIdentifies the sub-counter for selection and is passed to its onClick. Falls back to <parent key>-sub-<index> when omitted.
titlestringNoPreferred over label.
labelstringNoOlder name for title, kept so existing data keeps working. title wins when both are set.
valuenumberYesThe number the sub-counter counts up to, formatted like a KPI's value.
iconReact.ReactNodeNoIcon shown before the sub-counter's title.
colorstringNoColour of the sub-counter's value and of its hover and selected tint. Falls back to the parent KPI's color for the tint.
isCurrencybooleanNoPuts a currency symbol before the sub-counter's value, as on a KPI.
onClick(key: string) => voidNoCalled with the sub-counter's key (its own key, or <parent key>-sub-<index>) when it is clicked. Requires enableSubCounterClick; the parent's onClick does not fire.
disabledbooleanNoIgnores clicks and hover callbacks on the sub-counter and never shows it as selected.
badgeKPIBadgeNoBadge displayed alongside the title in the 'card' variant.
subtextstringNoSubtext displayed next to the count in the 'card' variant.
prefixstringNoText displayed before the value (e.g. a currency symbol or label).
suffixstringNoText displayed after the value (e.g. a unit like "kg" or "%").
abbreviationFormatAbbreviationFormatNoOverrides the component-level abbreviationFormat for this entry only.
abbreviationUnitAbbreviationUnitNoForces this entry's value into a fixed unit (e.g. show 2L as "200K", 4Cr as "400L"), overriding the auto-scale. Overrides the component-level abbreviationUnit.
abbreviationDecimalsnumberNoOverrides the component-level abbreviationDecimals for this entry only.
valueDecimalsnumberNoOverrides the component-level valueDecimals for this entry only.
abbreviatebooleanNoOverrides the component-level abbreviateCountUp for this entry only. Set true to abbreviate just this entry (or false to keep it full) while the rest follow the component default.

kpis.subCounters.badge​

An object (KPIBadge) with these fields:

FieldTypeRequiredDescription
textstringYesText of the badge shown after the sub-counter's title. Shown in the card variant only.
variant"default" | "success" | "info"NoColour of the badge: default (neutral), success or info. Defaults to default.

kpis.badge​

An object (KPIBadge) with these fields:

FieldTypeRequiredDescription
textstringYesText of the badge shown in the card header, before the icon. Shown in the card variant only.
variant"default" | "success" | "info"NoColour of the badge: default (neutral), success or info. Defaults to default.

Events​

NameSignatureWhen it fires
onReorder((updatedKpis: KPI[]) => void)Fires after the user drags a KPI to a new position in the draggable variant. Receives the reordered kpis array.
onActiveKPIChange((key: string | null) => void)Fires with the newly active key, or null when the selection is cleared.

The key is a KPI's key for a KPI click, and the sub-counter's resolved key for a sub-counter click (its own key, or <parent key>-sub-<index>). So this will not always match an entry in kpis — look through kpi.subCounters as well when resolving it. The parent stays highlighted either way.
onKPIMouseEnter((key: string, event: MouseEvent<HTMLDivElement, MouseEvent>) => void)Fires when the pointer enters a KPI. Keys resolve as for onActiveKPIChange: with enableSubCounterClick, entering a sub-counter also fires with the sub-counter's key while the KPI around it stays entered. Not fired for disabled KPIs or sub-counters.
onKPIMouseLeave((key: string, event: MouseEvent<HTMLDivElement, MouseEvent>) => void)Counterpart of onKPIMouseEnter, with the same keys.

Children​

Counter does not accept children.

Type definitions​

Shapes used by the properties above.

AbbreviationFormat​

type AbbreviationFormat = "international" | "indian";

AbbreviationUnit​

Units that a value can be forcibly abbreviated into, regardless of magnitude.

type AbbreviationUnit = "K" | "L" | "Cr" | "M" | "B";

Usage notes​

  • Choose a variant: default shows a row of counters with a caret on the selected one, card shows KPI cards that wrap after cardsPerRow, and draggable shows a scrollable row the user can reorder.
  • Sub-counters render in the default and card variants. The draggable variant ignores them.
  • Selection: leave activeKpi unset to let the component track the selected KPI, or pass activeKpi with setActiveKpi to control it. When enableSubCounterClick is on, the reported key can be a sub-counter's key, so look in kpi.subCounters too when you resolve it.
  • Per-KPI settings (abbreviate, abbreviationFormat, abbreviationUnit, abbreviationDecimals, valueDecimals) override the component-level ones for that KPI only.

Variants​

Loading examples…

Playground​

Change the controls to see how the properties affect the component. Values the controls don't cover come from the Default example.

Loading playground…

Storybook​

Open Counter in Storybook to try every story with the full set of controls.