Skip to main content

Overview

The Counter component displays an animated flip-clock style counter that animates from zero (or starting value) to the target amount. Each digit flips individually for a mechanical counter effect.

Import

import { Counter } from '@adoptaunabuelo/react-components';

Usage

Basic Counter

<Counter 
  amount={12345}
  height={60}
  width={40}
  fontSize={32}
/>

Custom Colors

import ColorV2 from '@adoptaunabuelo/react-components/constants/ColorV2';

<Counter 
  amount={999}
  height={50}
  width={35}
  fontSize={28}
  color={ColorV2.text.white}
  backgroundColor={ColorV2.surface.primary}
  borderColor={ColorV2.line.medium}
/>

Large Display Counter

<Counter 
  amount={5000}
  height={100}
  width={70}
  fontSize={56}
  color="#fff"
  backgroundColor="#1976d2"
/>

Small Counter

<Counter 
  amount={42}
  height={40}
  width={28}
  fontSize={24}
/>

Dynamic Counter

const [count, setCount] = useState(0);

<Counter 
  amount={count}
  height={60}
  width={40}
  fontSize={32}
/>

<button onClick={() => setCount(count + 100)}>
  Add 100
</button>

Props

amount
number
required
Target number to count up to.The component automatically:
  • Starts from amount - 10 (or 0 if amount < 10)
  • Counts up by 1 every 400ms
  • Stops when reaching the target amount
  • Restarts animation when amount changes
height
number
required
Height in pixels for each digit block.
height={60} // 60px tall digits
width
number
required
Width in pixels for each digit block.
width={40} // 40px wide digits
fontSize
number
Font size in pixels for the numbers.Typically set to ~80% of height for proper visual balance.
fontSize={32} // Works well with height={40}
color
string
Text color for the digits.Default: Inherits from CSS variables
backgroundColor
string
Background color for each digit block.Default: Inherits from CSS variables
borderColor
string
Border/divider color between digit segments.Used for the horizontal line separating top and bottom halves of each digit.Default: Inherits from CSS variables

Features

  • Flip animation: Each digit flips individually like a mechanical counter
  • Auto-start counting: Begins from amount - 10 and counts to target
  • Dynamic updates: Re-animates when amount prop changes
  • Customizable styling: Full control over colors, sizes, and typography
  • Multi-digit support: Automatically handles any number of digits
  • Smooth transitions: 400ms intervals for natural counting effect
  • CSS-based animations: Uses CSS modules for performant animations

Animation Behavior

  1. Initial render: Sets counter to amount - 10 (or 0 if amount < 10)
  2. Animation starts: After mount, increments by 1 every 400ms
  3. Completion: Stops when counter reaches target amount
  4. Re-animation: Resets and re-animates when amount prop changes
// Example: Counting from 90 to 100
<Counter amount={100} height={50} width={35} fontSize={28} />
// Animates: 90 → 91 → 92 → ... → 100
// Duration: ~4 seconds (10 steps × 400ms)

Digit Flip Mechanism

Each digit consists of two halves:
  • Top half: Shows current digit
  • Bottom half: Shows next digit
  • Animation: Rotates 180° when value changes
  • Result: Smooth flip transition between digits

Size Guidelines

Recommended proportions for balanced appearance:
HeightWidthFont SizeUse Case
40px28px24pxSmall counters, mobile
60px40px32pxStandard desktop
80px55px44pxLarge displays
100px70px56pxHero sections
General formula: width ≈ height × 0.7, fontSize ≈ height × 0.8

CSS Variables

The component uses CSS custom properties for theming:
--fcc-digit-color: text color
--fcc-background: background color
--fcc-digit-block-width: width in px
--fcc-digit-block-height: height in px
--fcc-digit-font-size: font size in px
--fcc-divider-color: border color
These are set automatically from props, but can be overridden via CSS if needed.

Performance Considerations

  • Uses window.setInterval for counting animation
  • Automatically clears interval on unmount
  • Re-creates interval when amount changes
  • CSS animations handled by GPU for smooth performance
  • Recommended for amounts < 1,000,000 (digit count affects rendering)

Best Practices

  • Match fontSize to height for visual balance (typically 80% of height)
  • Use contrasting colors for readability
  • Keep digit blocks consistent size across your app
  • Consider loading state while calculating amounts
  • Use for impressive number reveals (stats, metrics, achievements)
  • Avoid rapid amount changes (animation needs time to complete)
  • Test with maximum expected digit count for layout stability

Use Cases

  • Statistics dashboards: User counts, revenue, metrics
  • Achievement screens: Points, scores, milestones
  • Landing pages: Impressive numbers (customers, downloads)
  • Gamification: Score counters, level progression
  • Analytics: Real-time visitor counts
  • Countdowns: Days until event (when counting up from 0)

Accessibility

  • Uses data-testid="fcc-container" for testing
  • Semantic HTML structure
  • Consider adding aria-label with final count:
<div aria-label={`Count: ${amount}`}>
  <Counter amount={amount} height={60} width={40} fontSize={32} />
</div>

Browser Support

  • Modern browsers (Chrome, Firefox, Safari, Edge)
  • Requires CSS animations support
  • Uses window.setInterval (widely supported)

Troubleshooting

Counter doesn’t animate:
  • Check that amount prop is changing
  • Ensure component is mounted when amount updates
Digits appear cut off:
  • Increase width prop
  • Adjust parent container’s overflow property
Animation is too fast/slow:
  • Currently fixed at 400ms intervals
  • Modify source code if custom timing is needed
Numbers don’t fit in blocks:
  • Increase fontSize or decrease height/width
  • Check font-family renders at expected size
  • ProgressBar - Alternative progress indicator
  • Text - For static number display
  • Label - For badge-style counters

Build docs developers (and LLMs) love