← Components/Data Display

FlipCounter

flipcounter-1779388705785.tsx
'use client';
import { useState, useEffect } from 'react';

function FlipDigit({ digit, prev }) {
  const [flipping, setFlipping] = useState(false);

  useEffect(() => {
    if (digit !== prev) {
      setFlipping(true);
      const t = setTimeout(() => setFlipping(false), 400);
      return () => clearTimeout(t);
    }
  }, [digit, prev]);

  return (
    <div style={{
      width: '48px', height: '64px',
      background: '#1a1a1a',
      border: '1px solid rgba(255,255,255,0.1)',
      borderRadius: '8px',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      position: 'relative', overflow: 'hidden',
      boxShadow: 'inset 0 2px 8px rgba(0,0,0,0.4)',
    }}>
      <div style={{
        position: 'absolute', top: 0, left: 0, right: 0, height: '50%',
        borderBottom: '1px solid rgba(0,0,0,0.5)',
        background: 'rgba(0,0,0,0.2)',
      }} />
      <span style={{
        fontSize: '36px', fontWeight: 900, color: '#C9A84C',
        fontFamily: 'monospace',
        transform: flipping ? 'rotateX(90deg)' : 'rotateX(0deg)',
        transition: flipping ? 'transform 0.2s ease-in' : 'transform 0.2s ease-out',
        display: 'block',
        textShadow: '0 0 20px rgba(201,168,76,0.5)',
      }}>{digit}</span>
    </div>
  );
}

export default function FlipCounter({ start = 0, end = 9999, duration = 4000 }) {
  const [count, setCount] = useState(start);
  const [prev, setPrev] = useState(start);

  useEffect(() => {
    const steps = 60;
    const inc = (end - start) / steps;
    let current = start;
    const interval = setInterval(() => {
      current = Math.min(end, current + inc);
      setPrev(count => count);
      setCount(Math.round(current));
      if (current >= end) clearInterval(interval);
    }, duration / steps);
    return () => clearInterval(interval);
  }, [start, end, duration]);

  const digits = String(count).padStart(4, '0').split('');
  const prevDigits = String(prev).padStart(4, '0').split('');

  return (
    <div style={{ fontFamily: 'system-ui, sans-serif', display: 'inline-flex', flexDirection: 'column', alignItems: 'center', gap: '12px' }}>
      <div style={{ display: 'flex', gap: '6px', alignItems: 'center' }}>
        {digits.map((d, i) => (
          <FlipDigit key={i} digit={d} prev={prevDigits[i]} />
        ))}
      </div>
      <p style={{ margin: 0, color: 'rgba(245,245,240,0.4)', fontSize: '12px', letterSpacing: '0.1em', textTransform: 'uppercase' }}>
        Active Users
      </p>
    </div>
  );
}

Component info

CategoryData Display
Frameworkreact
TierFREE
Views0
Copies0

About

Mechanical flip-style animated counter

More from Data Display

'use client'
import { useState, useRef, useCallback, useEffect } from 'react'

export default function ComparisonSlider() {
  const [position, setPosition] = useState(50)
  const [dragging, setDragging] = useState(false)
  const containerRef = useRef
ComparisonSlider
Data Display
'use client'
import { useState } from 'react'

const WEEKS = 26
const DAYS = 7

function randomActivity(): number {
  const r = Math.random()
  if (r < 0.3) return 0
  if (r < 0.55) return 1
  if (r < 0.75) return 2
  if (r < 0.9) return 3
  return 4
HeatmapCalendar
Data Display
'use client'
import { useState } from 'react'

const events = [
  { id: 1, icon: '🚀', title: 'Wave 7 generation complete', desc: '57 new components published across 14 categories', time: '14:32', type: 'success', day: 'Today' },
  { id: 2, icon: '👥
TimelineActivity
Data Display
'use client';
import { useState } from 'react';

export default function SearchFilterBar() {
  const [query, setQuery] = useState('');
  const [filters, setFilters] = useState([]);
  const [showDropdown, setShowDropdown] = useState(false);

  const f
SearchFilterBar
Data Display