React · React Native · 16 components

Hard interactions, finished.

Animated Chorus is a set of motion components for the interactions that are hard to get right by hand: rolling numbers, streamed text, swaps that resize, sheets, pagers, swipe actions and lists that animate only what changed. One tag and your data. No provider, no setup.

Install
npm install @kkwaenggwari/animated-chorus

Measured on this build

Chrome, 2026-09-28. Every condition and sample is in the performance guide. How it was measured

  • 28.0KBKB gzip for all 16 exports

    The whole web entry, minified. React is the only peer.

  • 0JS frame callbacks while animating

    A number, a height and a highlight changing together: the browser plays all 12 animations.

  • 1React commit per value change

    MotionNumber renders when the value changes, never while it rolls.

  • 11React commits for 3000 streamed characters

    MotionStream appends characters directly and folds them into React a few times per second.

01Easiest

One tag and your data

Every component works on its own: no provider, wrapper component or setup call. Collections take items and renderItem, and your layout, text and styles stay yours.

  • Import one component and pass a value. That is the whole integration.
  • Lists, tabs and pagers read your array; keys default to item.id.
  • Text stays real text: it wraps, scales with the font and can be selected.
  • <MotionNumber value={total} />;
  • <MotionSwap value={status}>{label}</MotionSwap>;
  • <MotionHeight open={open}>{details}</MotionHeight>;
  • <MotionHighlight items={tabs} value={tab} onValueChange={setTab} />;
  • <MotionList items={tasks} renderItem={(task) => task.title} />;
  • <ProgressRing value={progress} />;

Six live components, and the one line of code behind each.

Preparing the example…

02Fastest

The browser plays it. React stays still.

On the web there is no animation library to load: components hand their motion to the Web Animations API, so a rolling number or a resizing panel costs no JavaScript per frame and no React render while it moves.

  • 0 JS frame callbacks while 12 animations run together.
  • One React commit per value change, not one per frame.
  • Streamed text: 11 React commits for 3000 characters. The example below counts its own renders.

Preparing the example…

03Most stable

Interrupt anything. It never jumps.

Every new value starts from what is on screen and springs keep their speed, so rapid clicks, bursts of data and reversals look intentional. When the motion ends, nothing is left running.

  • Numbers never split: remaining places slide while they roll.
  • 200 new values 5 ms apart: 0 animations left afterwards and the exact final text.
  • Safe under React StrictMode. In a background React Native app, motion settles to its end state.

Preparing the example…

The same import on the web and React Native

Metro selects the native implementation and web bundlers select the DOM one. Each platform plays motion the way it plays best.

App.jsx
// Web and React Native: the same import.
import { MotionNumber, MotionList } from '@kkwaenggwari/animated-chorus';

export function Score({ points, players }) {
  return (
    <>
      <MotionNumber value={points} />
      <MotionList items={players} renderItem={(player) => player.name} />
    </>
  );
}
PartWebReact Native
Transforms and opacityWeb Animations API, springs sampled analyticallyAnimated with the native driver
Width and heightWeb Animations APIAnimated with the JS driver, because it is layout
Streamed textCharacters appended and faded in; a few React renders per secondA real Text, revealed without a fade
Sheets and zoomA native dialog in the top layerA transparent Modal; the back button closes it

Start in two minutes

Install, import one component, pass a value.

npm install @kkwaenggwari/animated-chorus

Search

Type to search the documentation.