Number Formatting
Add nds-number-format to any element containing a number. The formatter applies locale-appropriate thousand separators on page load, preserving surrounding text, signs, and decimals.
<span class="nds-number-format">3240000</span>
<!-- Renders: 3,240,000 -->
<span class="nds-number-format">1850</span>
<!-- Renders: 1,850 -->
<span class="nds-number-format">42850.75</span>
<!-- Renders: 42,850.75 -->
<!-- Signs are preserved -->
<span class="nds-number-format">+2500</span>
<!-- Renders: +2,500 -->
<span class="nds-number-format">-340</span>
<!-- Renders: -340 -->
Counter Animation
Add nds-counter-value and set data-target to the final value. The counter animates from zero when the element scrolls into view. Combine with nds-number-format to apply thousand separators to the final value.
Government Services
Citizens Served
Satisfaction Rate
<span class="nds-counter-value nds-number-format"
data-target="1850">0</span>
<span class="nds-counter-value nds-number-format"
data-target="3240000">0</span>
<!-- Suffix in data-target is preserved -->
<span class="nds-counter-value nds-number-format"
data-target="98.5%">0</span>
Custom start — data-start="5000"
Custom duration — data-duration="3000"
No decimals — data-decimals="0"
<!-- Custom start value -->
<span class="nds-counter-value nds-number-format"
data-target="8500" data-start="5000"
data-duration="2000">0</span>
<!-- Custom duration (3 seconds) -->
<span class="nds-counter-value nds-number-format"
data-target="3240000" data-duration="3000">0</span>
<!-- Force no decimal places -->
<span class="nds-counter-value nds-number-format"
data-target="42850.75" data-decimals="0">0</span>
Currency
Add data-currency to any nds-number-format element to append the currency symbol automatically. SAR renders as the official Saudi Riyal SVG icon; other currencies use their Unicode symbols.
<!-- SAR: official Saudi Riyal SVG icon via CSS mask -->
<span class="nds-number-format" data-currency="SAR">450000</span>
<span class="nds-number-format" data-currency="USD">99999.99</span>
<span class="nds-number-format" data-currency="EUR">75000</span>
<!-- data-free: hides the currency icon for zero-price items -->
<span class="nds-number-format" data-currency="SAR" data-free>Free</span>
Annual Budget
Revenue
Savings
<span class="nds-counter-value nds-number-format"
data-currency="SAR" data-target="450000"
data-duration="2000">0</span>
<span class="nds-counter-value nds-number-format"
data-currency="SAR" data-target="128750"
data-duration="2000">0</span>
<span class="nds-counter-value nds-number-format"
data-currency="SAR" data-target="43200"
data-duration="2000">0</span>
Built-in Features
Both number formatting and counter animations activate automatically on page load with no extra JavaScript required.
Numbers are formatted with thousand separators based on the user's browser locale, preserving any surrounding text, signs, or suffixes.
Add data-currency for automatic currency symbols including SAR (Saudi Riyal icon), USD, EUR, GBP, JPY, CNY, INR, KRW, and TRY.
Counter animations begin when the element scrolls into view, with configurable start value, target, duration, and decimal precision.
Users who prefer reduced motion see the final counter value immediately with no animation, respecting the prefers-reduced-motion media query.
Call NDS.Numbers.reinit() after dynamically adding numbers to format and animate new elements.
Usage Guidelines
Best Practices
- Use
nds-number-formaton any element displaying a large number (thousands or more) to improve readability with locale-appropriate separators - Use
nds-counter-valuefor hero statistics, KPI dashboards, and landing page metrics where counting animation draws attention to key figures - Combine both classes (
nds-counter-value nds-number-format) so that the final counter value also receives thousand separators - Do not use counter animations for frequently updated live data or values that change on user interaction — counters are designed to play once on scroll
- Prefer
data-currencyover manually adding currency symbols; the attribute handles RTL/LTR symbol placement automatically - Set
data-durationbetween 800 and 2000 ms — shorter durations feel abrupt, longer ones delay comprehension - Use
data-decimalsto control precision; omit it to auto-detect from the target value, or set it to0for whole numbers - Place the raw number as the element's text content — the formatter parses it on load, so the number remains visible even before JavaScript runs
- Pair counters with statistic cards for a polished dashboard layout
Data Attributes
| Attribute | Default | Description |
|---|---|---|
data-currency |
none | Set on .nds-number-format. Supported values: SAR, USD, EUR, GBP, JPY, CNY, INR, KRW, TRY |
data-free |
absent | Set on .nds-number-format to suppress the currency symbol. Pair with a text label such as "Free" or "مجاني" for zero-price items. |
data-target |
Element text | Set on .nds-counter-value. Target number to count to. A suffix in the value (e.g. "98.5%") is preserved and appended to the animated number. |
data-start |
0 | Starting number for the counter animation |
data-duration |
1000 | Animation duration in milliseconds |
data-decimals |
auto | Force specific decimal places. When not set, matches decimals in data-target. Set to 0 to display whole numbers only. |
CSS Custom Properties
| Property | Default | Description |
|---|---|---|
--number-icon-size |
1em | Size of currency icons and child .nds-icon elements inside a formatted number |
JavaScript API
The NDS.Numbers module initializes automatically on page load. Call NDS.Numbers.reinit() after dynamically adding elements to the page.
// ── Format numbers on the page ──────────────────────
// Finds all .nds-number-format elements and applies
// locale-appropriate thousand separators
NDS.Numbers.formatNumbers();
// ── Start counter animations ─────────────────────────
// Observes all .nds-counter-value elements and animates
// them when they scroll into view
NDS.Numbers.setupCounterAnimations();
// ── Re-initialize everything ─────────────────────────
// Runs both formatNumbers() and setupCounterAnimations()
// Call after dynamically adding new number elements
NDS.Numbers.reinit();