Stats Section One
navdeep-singh/stats-section-oneFreeBlock
A business results section that combines measurable outcomes with a customer proof point.
Install it
npx shadcn@latest add https://ui.navdeepsingh.dev/r/stats-section-one.jsonSource
1'use client'23import type { ComponentProps } from 'react'4import { useEffect, useMemo, useRef } from 'react'5import {6 animate,7 motion,8 useInView,9 useMotionValue,10 useReducedMotion,11 useTransform,12} from 'motion/react'1314import { cn } from '@/lib/utils'1516export type BusinessMetric = {17 value: number18 label: string19 detail?: string20 prefix?: string21 suffix?: string22 decimals?: number23}2425export type AnimatedStatValueProps = {26 value: number27 prefix?: string28 suffix?: string29 decimals?: number30 duration?: number31 className?: string32}3334export type StatsSectionOneProps = ComponentProps<'section'> & {35 eyebrow?: string36 heading?: string37 description?: string38 metrics?: readonly BusinessMetric[]39}4041const defaultMetrics: readonly BusinessMetric[] = [42 {43 value: 38,44 suffix: '%',45 label: 'Faster delivery',46 detail: 'Within the first 90 days',47 },48 {49 value: 18,50 suffix: ' hrs',51 label: 'Saved every week',52 detail: 'Per operations team',53 },54 {55 value: 3.2,56 suffix: '×',57 decimals: 1,58 label: 'Return on spend',59 detail: 'Measured over 12 months',60 },61 {62 value: 99.9,63 suffix: '%',64 decimals: 1,65 label: 'Platform uptime',66 detail: 'Across all workspaces',67 },68]6970export function AnimatedStatValue({71 value,72 prefix = '',73 suffix = '',74 decimals = 0,75 duration = 1.1,76 className,77}: AnimatedStatValueProps) {78 const ref = useRef<HTMLSpanElement>(null)79 const shouldReduceMotion = useReducedMotion()80 const isInView = useInView(ref, {81 once: true,82 amount: 0.6,83 })8485 const animatedValue = useMotionValue(shouldReduceMotion ? value : 0)8687 const formatter = useMemo(88 () =>89 new Intl.NumberFormat('en-US', {90 minimumFractionDigits: decimals,91 maximumFractionDigits: decimals,92 }),93 [decimals],94 )9596 const formattedValue = useTransform(97 animatedValue,98 (latest) => `${prefix}${formatter.format(latest)}${suffix}`,99 )100101 const finalValue = `${prefix}${formatter.format(value)}${suffix}`102103 useEffect(() => {104 if (!isInView) return105106 if (shouldReduceMotion) {107 animatedValue.set(value)108 return109 }110111 const controls = animate(animatedValue, value, {112 duration,113 ease: [0.22, 1, 0.36, 1],114 })115116 return () => controls.stop()117 }, [animatedValue, duration, isInView, shouldReduceMotion, value])118119 return (120 <span ref={ref} className={cn('inline-block tabular-nums', className)}>121// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from navdeep-singh
All 64 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Blog Section Oneblog-section-one | navdeep-singh | Blocks | Free | 1 dep | |
| Contact Section Fourcontact-section-four | navdeep-singh | Blocks | Free | no deps | |
| Contact Section Onecontact-section-one | navdeep-singh | Blocks | Free | 1 dep | |
| Contact Section Threecontact-section-three | navdeep-singh | Blocks | Free | no deps | |
| Contact Section Twocontact-section-two | navdeep-singh | Blocks | Free | no deps | |
| Content Section Fourcontent-section-four | navdeep-singh | Blocks | Free | 1 dep | |
| Content Section Onecontent-section-one | navdeep-singh | Blocks | Free | 1 dep | |
| Content Section Threecontent-section-three | navdeep-singh | Blocks | Free | 2 deps |
