CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-react-countup

A configurable React component wrapper around CountUp.js for animated number counting effects

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

index.mddocs/

React CountUp

React CountUp is a configurable React component wrapper around CountUp.js that provides animated number counting effects. It offers both declarative component usage and imperative hook-based control with full TypeScript support.

Package Information

  • Package Name: react-countup
  • Package Type: npm
  • Language: TypeScript
  • Installation: npm install react-countup

Core Imports

import CountUp, { useCountUp, type CountUpProps } from "react-countup";

For CommonJS:

const CountUp = require("react-countup").default;
const { useCountUp } = require("react-countup");

Basic Usage

import React from "react";
import CountUp from "react-countup";

// Simple declarative usage
function App() {
  return (
    <div>
      <CountUp end={100} duration={2} />
    </div>
  );
}

// With custom formatting
function FormattedCounter() {
  return (
    <CountUp
      start={0}
      end={1234567}
      duration={3}
      separator=","
      prefix="$"
      suffix=" USD"
      decimals={2}
    />
  );
}

Architecture

React CountUp is built around three key components:

  • CountUp Component: Declarative React component supporting both standard rendering and render prop patterns
  • useCountUp Hook: Imperative hook providing programmatic control over animations with lifecycle management
  • CountUp.js Integration: Leverages the underlying CountUp.js library with React-specific optimizations and SSR compatibility

Capabilities

CountUp Component

React component wrapper providing declarative animated counting with extensive customization options and render prop support.

/**
 * React component for animated number counting
 */
declare const CountUp: React.FC<CountUpProps>;

interface CountUpProps extends CommonProps, CallbackProps {
  /** CSS class name for the container element */
  className?: string;
  /** Force redraw on every prop change */
  redraw?: boolean;
  /** Render prop function for custom rendering */
  children?: (props: RenderCounterProps) => React.ReactNode;
  /** Inline styles for the container element */
  style?: React.CSSProperties;
  /** Preserve current value when updating end value */
  preserveValue?: boolean;
  /** Additional props for the container span element */
  containerProps?: React.ComponentPropsWithoutRef<'span'>;
}

interface RenderCounterProps extends CountUpApi {
  /** Ref to attach to custom render element */
  countUpRef: React.RefObject<HTMLElement>;
}

Usage Examples:

import React from "react";
import CountUp from "react-countup";

// Standard usage
<CountUp end={100} duration={2} />

// With render prop for custom styling
<CountUp end={100} duration={2}>
  {({ countUpRef, start, reset }) => (
    <div>
      <span ref={countUpRef} className="big-number" />
      <button onClick={start}>Start</button>
      <button onClick={reset}>Reset</button>
    </div>
  )}
</CountUp>

// With event callbacks
<CountUp
  end={100}
  duration={2}
  onEnd={({ reset, start }) => console.log("Animation completed!")}
  onStart={() => console.log("Animation started!")}
/>

useCountUp Hook

Hook providing imperative control over CountUp animations with lifecycle management and programmatic API access.

/**
 * Hook for imperative CountUp control
 * @param props Configuration options for the counter
 * @returns API object with control methods
 */
function useCountUp(props: UseCountUpProps): CountUpApi;

interface UseCountUpProps extends CommonProps, CallbackProps {
  /** Target element reference (string selector or React ref) */
  ref: string | React.RefObject<HTMLElement>;
  /** Whether to reinitialize when props change */
  enableReinitialize?: boolean;
}

interface CountUpApi {
  /** Start or restart the animation */
  start: () => void;
  /** Pause or resume the animation */
  pauseResume: () => void;
  /** Reset the counter to start value */
  reset: () => void;
  /** Update the end value and animate to it */
  update: (newEnd: string | number) => void;
  /** Get the underlying CountUp.js instance */
  getCountUp: (recreate?: boolean) => CountUpInstance;
}

Usage Examples:

import React, { useRef } from "react";
import { useCountUp } from "react-countup";

function CustomCounter() {
  const countUpRef = useRef<HTMLSpanElement>(null);
  
  const { start, reset, update, pauseResume } = useCountUp({
    ref: countUpRef,
    end: 100,
    duration: 2,
    startOnMount: false,
  });

  return (
    <div>
      <span ref={countUpRef} />
      <button onClick={start}>Start</button>
      <button onClick={pauseResume}>Pause/Resume</button>
      <button onClick={reset}>Reset</button>
      <button onClick={() => update(200)}>Update to 200</button>
    </div>
  );
}

// With string selector
function SelectorCounter() {
  useCountUp({
    ref: 'counter-element',
    end: 100,
    duration: 2,
  });

  return <div id="counter-element" />;
}

Common Configuration

Core Props Interface

Shared configuration options available to both component and hook.

interface CommonProps extends CountUpInstanceProps {
  /** Whether to start animation on mount */
  startOnMount?: boolean;
  /** Delay before starting animation (in seconds) */
  delay?: number | null;
}

interface CountUpInstanceProps extends CountUpOptions {
  /** Number of decimal places to display */
  decimals?: number;
  /** The target end value */
  end: number;
  /** The starting value */
  start?: number;
  /** Whether to use easing animation */
  useEasing?: boolean;
}

Event Callbacks

Complete event callback system for animation lifecycle management.

interface CallbackProps {
  /** Called when animation ends */
  onEnd?: OnEndCallback;
  /** Called when animation starts */
  onStart?: OnStartCallback;
  /** Called when animation is paused/resumed */
  onPauseResume?: OnPauseResumeCallback;
  /** Called when counter is reset */
  onReset?: OnResetCallback;
  /** Called when end value is updated */
  onUpdate?: OnUpdateCallback;
}

type OnEndCallback = (args: OnEndArgs) => void;
type OnStartCallback = (args: OnStartArgs) => void;
type OnPauseResumeCallback = (args: OnPauseResumeArgs) => void;
type OnResetCallback = (args: OnResetArgs) => void;
type OnUpdateCallback = (args: OnUpdateArgs) => void;

interface OnEndArgs {
  pauseResume: () => void;
  reset: () => void;
  start: () => void;
  update: (newEnd: string | number) => void;
}

interface OnStartArgs {
  pauseResume: () => void;
  reset: () => void;
  update: (newEnd: string | number) => void;
}

interface OnPauseResumeArgs {
  reset: () => void;
  start: () => void;
  update: (newEnd: string | number) => void;
}

interface OnResetArgs {
  pauseResume: () => void;
  start: () => void;
  update: (newEnd: string | number) => void;
}

interface OnUpdateArgs {
  pauseResume: () => void;
  reset: () => void;
  start: () => void;
}

CountUp.js Configuration Options

All configuration options from the underlying CountUp.js library are supported:

interface CountUpOptions {
  /** Decimal character */
  decimal?: string;
  /** Thousands separator character */
  separator?: string;
  /** Text prepended to result */
  prefix?: string;
  /** Text appended to result */
  suffix?: string;
  /** Animation duration in seconds */
  duration?: number;
  /** Whether to use easing animation */
  useEasing?: boolean;
  /** Whether to use thousands separator grouping */
  useGrouping?: boolean;
  /** Whether to use Indian number separators */
  useIndianSeparators?: boolean;
  /** Custom easing function */
  easingFn?: (t: number, b: number, c: number, d: number) => number;
  /** Custom formatting function */
  formattingFn?: (value: number) => string;
  /** Custom numerals array */
  numerals?: string[];
  /** Whether to enable scroll spy functionality */
  enableScrollSpy?: boolean;
  /** Scroll spy delay in milliseconds */
  scrollSpyDelay?: number;
  /** Whether scroll spy should trigger only once */
  scrollSpyOnce?: boolean;
  /** CountUp.js plugin */
  plugin?: any;
}

/** CountUp.js instance returned by getCountUp method */
interface CountUpInstance {
  /** Start the animation */
  start(callback?: () => void): void;
  /** Pause or resume the animation */
  pauseResume(): void;
  /** Reset to start value */
  reset(): void;
  /** Update to new end value */
  update(newEnd: number | string): void;
  /** Get formatted value at current state */
  formattingFn(value: number): string;
}

Default Values

The useCountUp hook provides sensible defaults for all configuration options:

const DEFAULTS = {
  decimal: '.',
  separator: ',',
  delay: null,
  prefix: '',
  suffix: '',
  duration: 2,
  start: 0,
  decimals: 0,
  startOnMount: true,
  enableReinitialize: true,
  useEasing: true,
  useGrouping: true,
  useIndianSeparators: false,
};

Advanced Usage Patterns

Conditional Animations

import React, { useState } from "react";
import CountUp from "react-countup";

function ConditionalCounter() {
  const [shouldAnimate, setShouldAnimate] = useState(false);

  return (
    <div>
      {shouldAnimate && (
        <CountUp
          end={100}
          duration={2}
          onEnd={() => setShouldAnimate(false)}
        />
      )}
      <button onClick={() => setShouldAnimate(true)}>
        Start Animation
      </button>
    </div>
  );
}

Multiple Counters with Synchronization

import React, { useRef } from "react";
import { useCountUp } from "react-countup";

function SynchronizedCounters() {
  const ref1 = useRef<HTMLSpanElement>(null);
  const ref2 = useRef<HTMLSpanElement>(null);
  
  const counter1 = useCountUp({
    ref: ref1,
    end: 100,
    duration: 2,
    startOnMount: false,
  });
  
  const counter2 = useCountUp({
    ref: ref2,
    end: 200,
    duration: 2,
    startOnMount: false,
  });

  const startBoth = () => {
    counter1.start();
    counter2.start();
  };

  return (
    <div>
      <span ref={ref1} /> | <span ref={ref2} />
      <button onClick={startBoth}>Start Both</button>
    </div>
  );
}

Custom Formatting with Callbacks

import CountUp from "react-countup";

function CustomFormattedCounter() {
  return (
    <CountUp
      end={1234567.89}
      decimals={2}
      duration={3}
      formattingFn={(value) => {
        // Custom currency formatting
        return new Intl.NumberFormat('en-US', {
          style: 'currency',
          currency: 'USD'
        }).format(value);
      }}
    />
  );
}

Error Handling

The library handles common error scenarios:

  • Missing DOM element: When using render props, the library logs a warning if countUpRef is not attached to a DOM element
  • Invalid values: Non-numeric end values are handled gracefully by CountUp.js
  • SSR compatibility: Uses useIsomorphicLayoutEffect to prevent hydration mismatches

TypeScript Support

React CountUp provides complete TypeScript definitions with:

  • Full type safety for all props and callback parameters
  • Generic type preservation where applicable
  • Comprehensive interface definitions for all API surfaces
  • Integration with React's built-in types (CSSProperties, RefObject, etc.)

Dependencies

  • Runtime: countup.js ^2.8.0
  • Peer Dependencies: react >= 16.3.0
  • No additional runtime dependencies

Install with Tessl CLI

npx tessl i tessl/npm-react-countup

docs

index.md

tile.json