
NumericText is a lightweight, framework-agnostic web component that animates text transitions between strings and numbers.
The library was designed to recreate the behavior and feel of SwiftUI’s .numericText() for the browser.
You can use it in vanilla JavaScript projects, install framework wrappers for React, Vue, Svelte, or Solid, or import the core package from an ESM CDN in browser-first webpages.
See It In Action:
Features:
- Animate numbers and arbitrary text.
- Run in vanilla JavaScript projects.
- Support React, Vue, Svelte, and Solid wrappers.
- Avoid third-party runtime dependencies.
- Keep the core package small.
- Respect reduced-motion preferences.
- Support RTL interface text.
- Preserve accessible screen reader labels.
Use Cases:
- Live dashboards show changing KPI values with less visual jump.
- Pricing tables highlight plan changes during billing updates.
- Scoreboards update player totals while keeping digits readable.
- Command palettes swap status labels in compact UI space.
How To Use It:
Installation
Install the core package for vanilla JavaScript.
npm install @numeric-text/core
Install a framework wrapper when your project renders UI through a component tree.
npm install @numeric-text/react
npm install @numeric-text/vue
npm install @numeric-text/svelte
npm install @numeric-text/solid
You can also import the core package from an ESM CDN for browser use.
<script type="module"> import 'https://esm.sh/@numeric-text/core'; </script>
Basic Usage
Add the custom element to your HTML, import the core package, then update the element value through JavaScript.
<numeric-text
id="checkoutTotal"
role="img"
aria-label="Checkout total is 118 dollars"
></numeric-text>
<script type="module">
// Registers the <numeric-text> custom element.
import '@numeric-text/core';
const checkoutTotal = document.querySelector('#checkoutTotal');
// Set the first value instantly.
checkoutTotal.value = 'Total $118';
// Animate the next text change.
setTimeout(() => {
checkoutTotal.setAttribute('aria-label', 'Checkout total is 124 dollars');
checkoutTotal.update('Total $124');
}, 1200);
</script>
The value property sets the displayed content. The update() method changes the content and animates the transition by default.
Advanced Usages
Dashboard refreshes often need instant replacement before fresh data arrives. The second argument turns animation off for a single vanilla JavaScript update.
const orderCount = document.querySelector('#orderCount');
// Replace the value instantly.
orderCount.update('Orders 1,240', false);
Financial interfaces sometimes need all digits to move downward during negative changes. The snippet sets a fixed downward direction before the next animated update.
const priceChange = document.querySelector('#priceChange');
// Force the transition direction downward.
priceChange.setOptions({
trend: -1,
});
priceChange.update('$48.20');
Ticker labels may need shorter motion than dashboard metrics. The snippet changes duration and easing for one element instance.
const stockLabel = document.querySelector('#stockLabel');
// Replace the default timing.
stockLabel.setOptions({
transition: {
duration: 320,
easing: 'ease-out',
},
});
stockLabel.update('AAPL 216.42');
React Implementation
import { useState } from 'react';
import NumericText from '@numeric-text/react';
export default function CartSummary() {
const [total, setTotal] = useState(86);
return (
<button onClick={() => setTotal(total + 12)}>
<NumericText value={`Cart total $${total}`} />
</button>
);
}
Vue Implementation
<script setup lang="ts">
import { ref } from 'vue';
import NumericText from '@numeric-text/vue';
const seatsLeft = ref(18);
function reserveSeat() {
seatsLeft.value -= 1;
}
</script>
<template>
<button @click="reserveSeat">
<NumericText :value="`${seatsLeft} seats left`" />
</button>
</template>
Svelte projects can pass a reactive variable into the wrapper. The text transition runs when the value changes.
<script lang="ts">
import NumericText from '@numeric-text/svelte';
let buildStatus = 'Queued';
</script>
<button on:click={() => (buildStatus = 'Running')}>
<NumericText value={buildStatus} />
</button>
All configuration options
value(string | number): Sets the text or number displayed by the component.animated(boolean): Controls animation in framework wrappers. For vanilla JavaScript, passfalseas the second argument toupdate().trend(1 | 0 | -1): Controls animation direction. Use1for upward motion,-1for downward motion, or0for automatic numeric direction.transition(Transition): Sets animation timing with a duration and easing function.respectMotionPreference(boolean): Disables animation when the user has enabled reduced motion in system settings.
API Methods
const metricText = document.querySelector('#metricText');
// Display a new value with the default animated transition.
metricText.update('Revenue +24%');
// Display a new value instantly in vanilla JavaScript.
metricText.update('Revenue +31%', false);
// Change animation timing, direction, and motion preference handling.
metricText.setOptions({
trend: 1,
transition: {
duration: 400,
easing: 'ease-out',
},
respectMotionPreference: true,
});
Alternatives:
- 10 Best Typewriter Text Animation JavaScript Libraries
- Torph: Animated Text Morphing for Vanilla JS, React, Vue, and More
- Morphing Text Effect With SVG And JavaScript
- Text Scramble/Shuffle Effect – scrambling-text-js
- Apply Smooth Animations to Text Using Data Attributes – AnimText.js
- CountUp.js Guide: Animated Number Counter Options & Examples
- Vanilla JS Library for Smooth Number Transitions – CounterAnime
FAQs:
Q: Does NumericText animate only numbers?
A: No. NumericText supports numbers and regular text strings. It works well for short labels, metric values, status text, prices, and counters.
Q: Why does my HTML attribute not update the text?
A: Set the value property or call update() on the element. The vanilla JavaScript API works through the custom element instance.
Q: Why does my text wrap or lose typographic details?
A: NumericText targets single-line UI text. It renders characters in separate spans, so multiline layout, ligatures, and kerning are not supported.
Q: What happens if I pass a value that contains special characters or emojis?
A: NumericText uses Intl.Segmenter with granularity: 'grapheme', so multi-codepoint emojis and combined characters are treated as a single unit. The animation and diffing remain correct across all Unicode scripts.







