{"id":11820,"library":"react-odometerjs","title":"React Odometer.js","description":"React Odometer.js is a wrapper component that integrates the Odometer.js library into React applications, providing animated numerical counters. The current stable version is 3.1.3. While it doesn't follow a strict release cadence, updates appear to coincide with significant React API changes or new features, such as the adoption of hooks in v3.0.0 for React 16.8+. Its primary differentiator is simplifying the use of Odometer.js within a React ecosystem, abstracting away direct DOM manipulation typically required by the underlying library. It ships with TypeScript types, enhancing developer experience and type safety. A key aspect of its usage is managing server-side rendering (SSR) environments like Next.js or Gatsby, where dynamic imports are necessary to prevent issues with Odometer.js's reliance on the browser's `document` object.","status":"active","version":"3.1.3","language":"javascript","source_language":"en","source_url":"https://github.com/bezenson/react-odometerjs","tags":["javascript","react","component","odometer","hubspot","js","react-component","typescript"],"install":[{"cmd":"npm install react-odometerjs","lang":"bash","label":"npm"},{"cmd":"yarn add react-odometerjs","lang":"bash","label":"yarn"},{"cmd":"pnpm add react-odometerjs","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Peer dependency for React applications, minimum version 16.8.0 for hooks.","package":"react","optional":false},{"reason":"Peer dependency for rendering React components.","package":"react-dom","optional":false}],"imports":[{"note":"The `Odometer` component is exported as a default export. Named or namespace imports for the component will fail.","wrong":"import { Odometer } from 'react-odometerjs';\nimport * as Odometer from 'react-odometerjs';","symbol":"Odometer","correct":"import Odometer from 'react-odometerjs';"},{"note":"While `react-odometerjs` is designed for ESM `import` statements, developers sometimes attempt to use CommonJS `require`. This can lead to issues in modern environments; prefer ESM imports.","wrong":"const Odometer = require('react-odometerjs');","symbol":"Odometer (CommonJS)","correct":"(Use ESM import)"},{"note":"For TypeScript projects, the component's props interface `OdometerProps` can be imported for type checking. Use `import type` to ensure it's a type-only import, preventing runtime overhead.","wrong":"import { OdometerProps } from 'react-odometerjs';","symbol":"OdometerProps","correct":"import type { OdometerProps } from 'react-odometerjs';"}],"quickstart":{"code":"import React, { useEffect, useState } from 'react';\nimport Odometer from 'react-odometerjs';\n// To use themes, you must install the original 'odometer' package:\n// npm install odometer\n// Then, import the desired theme's CSS file. Example for default theme:\nimport 'odometer/themes/odometer-theme-default.css';\n\nconst OdometerExample = () => {\n    const [value, setValue] = useState(1234);\n    const [isMounted, setIsMounted] = useState(false); // State to ensure Odometer is mounted on client-side\n\n    useEffect(() => {\n        // This ensures the Odometer component is only rendered client-side,\n        // which is crucial for Odometer.js as it relies on the 'document' object.\n        // For SSR frameworks, more robust dynamic imports are needed (see warnings).\n        setIsMounted(true);\n\n        const timeoutId = setTimeout(() => setValue(4321), 2000);\n        return () => {\n            clearTimeout(timeoutId);\n        };\n    }, []);\n\n    // Render a placeholder or nothing if not mounted to prevent SSR issues\n    if (!isMounted) {\n        return <div>Loading counter...</div>;\n    }\n\n    return (\n        <div style={{ padding: '20px', fontFamily: 'Arial, sans-serif' }}>\n            <h1>Animated Counter Example</h1>\n            <p>Watch the number change after 2 seconds:</p>\n            <Odometer\n                value={value}\n                format=\"(.ddd),dd\" // Example format: thousands separator and two decimal places (not shown here as value is integer)\n                theme=\"default\"    // Corresponds to 'odometer-theme-default.css'\n                animation=\"count\"  // Simple counting animation\n                duration={1500}    // Animation duration in milliseconds\n                style={{ fontSize: '4em', fontWeight: 'bold', color: '#007bff' }}\n            />\n            <p style={{ marginTop: '20px' }}>Current value: {value}</p>\n        </div>\n    );\n};\n\nexport default OdometerExample;","lang":"typescript","description":"This example demonstrates how to integrate `react-odometerjs` into a React component, updating its value after a delay to show the animation. It also highlights basic styling and essential CSS theme import requirements."},"warnings":[{"fix":"Upgrade your `react` and `react-dom` packages to at least `16.8.0`.","message":"Minimum React version increased to 16.8.0 due to the adoption of React Hooks, which are used internally by `react-odometerjs`.","severity":"breaking","affected_versions":">=3.0.0"},{"fix":"Refactor usage from `<Odometer value={1234} options={{ format: '(.ddd),dd' }} />` to `<Odometer value={1234} format='(.ddd),dd' />`.","message":"Odometer options are now passed directly as props to the component, rather than nested within an `options` object.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Remove the `selector` prop; the component now manages its own DOM element selection internally.","message":"The `selector` prop was removed as it had no effect when `auto: false`, which is the default configuration for this React wrapper.","severity":"deprecated","affected_versions":">=3.1.0"},{"fix":"Wrap the `react-odometerjs` component import with a dynamic import and `ssr: false` option. Refer to the Next.js or Gatsby integration examples in the documentation for specific implementation details.","message":"When using `react-odometerjs` with Server-Side Rendering (SSR) frameworks like Next.js or Gatsby, the underlying `Odometer.js` library directly accesses the browser's `document` object, leading to 'document is not defined' errors during server builds.","severity":"gotcha","affected_versions":"*"},{"fix":"Ensure you have installed the `odometer` npm package (`npm install odometer`) and then add a `<link rel=\"stylesheet\" href=\"odometer-theme-default.css\" />` to your `index.html` or import a theme CSS file in your main application entry point (e.g., `import 'odometer/themes/odometer-theme-default.css';`).","message":"To display correctly, `react-odometerjs` requires an Odometer.js CSS theme file to be manually imported into your application's `head` or component stylesheet.","severity":"gotcha","affected_versions":"*"},{"fix":"For type checking, rely on TypeScript's built-in type inference or import the `OdometerProps` interface; do not expect runtime PropTypes to be present.","message":"Runtime Prop Types are no longer bundled with the npm package since v2.1.0, relying instead on TypeScript types for type checking.","severity":"gotcha","affected_versions":">=2.1.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Use a dynamic import for the `Odometer` component with `ssr: false`. Example for Next.js: `const Odometer = dynamic(import('react-odometerjs'), { ssr: false, loading: () => 0 });`","cause":"Attempting to render `react-odometerjs` on the server-side in an SSR environment (e.g., Next.js, Gatsby) without dynamically importing it.","error":"ReferenceError: document is not defined"},{"fix":"Pass Odometer options directly as props to the component. Change `<Odometer value={1234} options={{ format: '(.ddd),dd' }} />` to `<Odometer value={1234} format=\"(.ddd),dd\" />`.","cause":"Passing Odometer options as an object to an `options` prop, which was deprecated and removed in v2.0.0.","error":"Objects are not valid as a React child (found: object with keys {format}). If you meant to render a collection of children, use an array instead."},{"fix":"Ensure that the `odometer` npm package is installed (`npm install odometer`) and a theme CSS file (e.g., `odometer/themes/odometer-theme-default.css`) is properly imported and applied globally or in the component's scope. Also, confirm the `theme` prop, if used, matches the imported CSS.","cause":"The Odometer.js library or its React wrapper attempts to access DOM elements before the required CSS theme is loaded or the component is properly mounted, or due to incorrect theme application.","error":"TypeError: Cannot read properties of null (reading 'style') OR Odometer is not defined"},{"fix":"Update your `react` and `react-dom` packages in your project to version `16.8.0` or higher to support React Hooks.","cause":"`react-odometerjs` v3.0.0+ utilizes React Hooks internally, but your project's `react` and `react-dom` peer dependencies are older than the required 16.8.0 version.","error":"Error: Invalid hook call. Hooks can only be called inside of the body of a function component."}],"ecosystem":"npm"}