Low stock line

Exact count from real inventory, hidden above the threshold and at zero. Plain ink, no urgency color.

componentstockanyinventory
$npx shadcn@latest add @storekit/pdp-low-stock
pdp-low-stock

Live and interactive. Switch the brand in the frame header to see the same source under another token file.

Installation

$npx shadcn@latest add @storekit/pdp-low-stock
$pnpm dlx shadcn@latest add @storekit/pdp-low-stock
$yarn dlx shadcn@latest add @storekit/pdp-low-stock
$bunx --bun shadcn@latest add @storekit/pdp-low-stock

Source

components/storekit/pdp/pdp-low-stock.tsx
63 lines
"use client"

import { AnimatePresence, motion, useReducedMotion } from "motion/react"
import { cn } from "@/components/storekit/lib/cn"

/* Exact low-stock line. Reads the real inventory count and renders nothing
   above the threshold or at zero (sold out is its own state). The copy is
   the number, not a nudge: no accent, no red, no timer. An optional meter
   shows the count against the threshold in plain ink. */

export function PdpLowStock({
  inventory,
  threshold = 10,
  variantLabel,
  restockNote,
  showMeter = true,
  className,
}: {
  /** Real units on hand for the selected variant. */
  inventory: number
  /** Show the line only at or below this count. */
  threshold?: number
  variantLabel?: string
  /** Optional honest follow up, e.g. "More arriving Nov 4". */
  restockNote?: string
  showMeter?: boolean
  className?: string
}) {
  const reduce = useReducedMotion()
  const visible = Number.isFinite(inventory) && inventory > 0 && inventory <= threshold
  const n = Math.floor(inventory)
  const copy = `${n} left${variantLabel ? ` in ${variantLabel}` : " in stock"}`
  const segments = Math.min(threshold, 10)
  const filled = Math.max(1, Math.round((n / threshold) * segments))

  return (
    <div data-sk-section="pdp" data-sk-variant="pdp-low-stock" className={cn("w-full", className)} aria-live="polite">
      <AnimatePresence initial={false} mode="popLayout">
        {visible ? (
          <motion.p
            key={copy}
            initial={{ opacity: 0, y: reduce ? 0 : 6 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: reduce ? 0 : -6 }}
            transition={{ duration: reduce ? 0 : 0.3, ease: [0.16, 1, 0.3, 1] }}
            className="flex flex-wrap items-center gap-x-3 gap-y-1.5 text-sm"
          >
            {showMeter ? (
              <span aria-hidden className="flex gap-[3px]">
                {Array.from({ length: segments }).map((_, i) => (
                  <span key={i} className={cn("h-2.5 w-1.5 rounded-[1px]", i < filled ? "bg-sk-ink" : "bg-sk-ink/15")} />
                ))}
              </span>
            ) : null}
            <span className="font-medium tabular-nums text-sk-ink">{copy}</span>
            {restockNote ? <span className="text-sk-muted">{restockNote}</span> : null}
          </motion.p>
        ) : null}
      </AnimatePresence>
    </div>
  )
}

Usage

Pass the live inventory count of the selected variant. Never pass a made up number.

Low stock line, StoreKit