はじめに
ダッシュボードの売上金額や、いいね数、在庫数——画面上の数字が更新されるとき、値がただ「パッと切り替わる」だけでは、ユーザーはその変化に気づきにくいものです。逆に、数字が桁ごとにくるくると回転しながら新しい値へ変わっていくアニメーションを見たことがある人は多いはずです。あの動きを自作しようとすると、桁ごとのDOM管理やタイミング制御が意外と面倒で、車輪の再発明になりがちです。
そこで今回紹介するのがNumber-Flowです。React・Vue・Svelte・素のJavaScriptのいずれからも使える、数値専用のアニメーションコンポーネントで、値を渡すだけで桁単位の滑らかなトランジションを実現してくれます。
Number-Flowとは
Number-Flowは、Maxime Barvian氏が開発しているアニメーション数値表示ライブラリです。GitHub上で7,000以上のスターを獲得しており、3,000以上のプロジェクトで使われています。Web ComponentsとCSSアニメーションをベースに実装されているため、フレームワークを問わず組み込める点が特徴です。
主な特徴
- フレームワーク横断対応 - React・Vue・Svelte向けの専用パッケージに加え、Web Componentsとしてバニラ環境でも利用できます
Intl.NumberFormatベースの書式指定 -formatpropにIntl.NumberFormatOptionsをそのまま渡せるため、通貨表示や桁区切り、パーセント表示などをネイティブAPIの知識だけで実現できます- 依存関係ゼロ - 外部ライブラリに依存しないスタンドアロン設計で、バンドルサイズへの影響を抑えられます
- アクセシビリティ対応 - スクリーンリーダー向けの配慮に加え、
respectMotionPreferenceによりOSの「視差効果を減らす」設定を尊重し、必要に応じてアニメーションを自動で抑制します
インストール
Reactで使う場合は、専用パッケージをインストールします。
npm install @number-flow/react
Vue・Svelteを使っている場合も、それぞれのパッケージが用意されています。
npm install @number-flow/vue
npm install @number-flow/svelte
フレームワークを使わない場合は、Web Components版をそのまま利用できます。
npm install number-flow
基本的な使い方
Reactでの最小構成は、valuepropに数値を渡すだけです。値が変化するたびに、自動でトランジションが発火します。
import NumberFlow from '@number-flow/react'
import { useState } from 'react'
function Counter() {
const [value, setValue] = useState(100)
return (
<div>
<NumberFlow value={value} />
<button onClick={() => setValue(value + 1)}>+1</button>
</div>
)
}
通貨や桁区切りなどの書式は、Intl.NumberFormatOptionsをそのままformatpropに渡せます。
import NumberFlow from '@number-flow/react'
function Price({ amount }: { amount: number }) {
return (
<NumberFlow
value={amount}
format={{ style: 'currency', currency: 'JPY' }}
/>
)
}
数値の増減方向を示したい場合はtrendpropを使います。1なら常に上向き、-1なら常に下向き、0なら実際の増減に応じてアニメーションの向きが決まります。
<NumberFlow value={score} trend={1} />
実践的なユースケース
ダッシュボードのKPIカード
売上や訪問者数などのKPIをリアルタイム更新するダッシュボードでは、値が変わったことをユーザーに視覚的に伝えることが重要です。ポーリングやWebSocketで受け取った値をそのままvalueに渡すだけで、更新の瞬間が自然に強調されます。
import NumberFlow from '@number-flow/react'
import { useEffect, useState } from 'react'
function RevenueCard() {
const [revenue, setRevenue] = useState(0)
useEffect(() => {
const id = setInterval(() => {
// サーバーから取得した最新の値を反映する想定
setRevenue((prev) => prev + Math.floor(Math.random() * 1000))
}, 3000)
return () => clearInterval(id)
}, [])
return (
<div className="kpi-card">
<p>今月の売上</p>
<NumberFlow
value={revenue}
format={{ style: 'currency', currency: 'JPY', maximumFractionDigits: 0 }}
/>
</div>
)
}
いいね数・カウント表示
SNSライクなUIの「いいね」ボタンにも相性が良く、ワンタップの操作に対するフィードバックとして数値アニメーションが機能します。
import NumberFlow from '@number-flow/react'
import { useState } from 'react'
function LikeButton({ initialCount }: { initialCount: number }) {
const [count, setCount] = useState(initialCount)
const [liked, setLiked] = useState(false)
const toggleLike = () => {
setCount((prev) => (liked ? prev - 1 : prev + 1))
setLiked(!liked)
}
return (
<button onClick={toggleLike}>
♥ <NumberFlow value={count} trend={0} />
</button>
)
}
途中経過を通過させたいプログレス表示
在庫カウントダウンやタイマーのように、値の変化そのものを見せたい場面ではcontinuousプラグインが役立ちます。通常のトランジションは目標値へ直接アニメーションしますが、continuousを使うと途中の数値を実際に通過させながら遷移させられます。
import NumberFlow, { continuous } from '@number-flow/react'
function StockCounter({ stock }: { stock: number }) {
return <NumberFlow value={stock} plugins={[continuous]} />
}
まとめ
Number-Flowは、数値の変化を「伝わるUI」に変えてくれるライブラリです。valueを渡すだけの手軽さでありながら、Intl.NumberFormatによる書式設定やtrendによる方向制御、アクセシビリティへの配慮まで揃っており、React・Vue・Svelteのどれを使っていても導入のハードルが低いのが魅力です。
ダッシュボードやカウンター表示で「数字がただ切り替わるだけ」に物足りなさを感じているなら、npm install @number-flow/reactから試してみてはいかがでしょうか。
