XP Bar

An RPG-styled experience progress bar tuned for leveling indicators in skill trees, lesson dashboards, and gamified onboarding. Takes three numeric props — level, xpInLevel, xpForNextLevel — so consumers don't pre-compute a percentage, then animates the fill from zero with SPRINGS.smooth. The fill color flows through currentColor so the inner glow and the level pill inherit the same hue automatically.

Preview
42 / 100 XP
180 / 250 XP
620 / 800 XP

Installation

npx shadcn@latest add https://craftbits.dev/r/xp-bar.json

Usage

import { XPBar } from "@craft-bits/core";
 
<XPBar level={3} xpInLevel={42} xpForNextLevel={100} />

Custom color and height:

<XPBar
  level={7}
  xpInLevel={180}
  xpForNextLevel={250}
  color="var(--cb-success)"
  height={10}
/>

Headless track (no level pill, no readout):

<XPBar level={1} xpInLevel={5} xpForNextLevel={50} hideLabel />

Anatomy

  • Level pill — a small Lv N chip with the fill color applied as color. Hide it with hideLabel.
  • Inset trackbg-cb-bg-muted with a subtle inset shadow so the fill reads as sitting inside a channel.
  • Glow fillbackgroundColor: currentColor + boxShadow: inset 0 0 6px currentColor so the fill has the RPG inner-glow look without a sprite sheet.
  • XP readout42 / 100 XP in a monospaced tabular-numbers font, formatted by the optional formatXP prop.

Props

PropTypeDefaultDescription
levelnumberrequiredCurrent level — shown in the leading pill.
xpInLevelnumberrequiredXP earned inside the current level (fill numerator).
xpForNextLevelnumberrequiredXP required to reach the next level (fill denominator). Must be > 0.
colorstring'var(--cb-accent)'Track + glow color. Accepts any CSS color.
heightnumber8Bar height in px.
delaynumber0Animation delay in seconds.
hideLabelbooleanfalseHide the leading level pill and trailing XP readout.
formatXP(xpInLevel, xpForNextLevel) => string"N / M XP"Formatter for the trailing readout.
classNamestringMerged onto the root via cn().

Accessibility

  • The fill track is a role="progressbar" with aria-valuenow / aria-valuemin / aria-valuemax so assistive tech announces the fill percentage.
  • The aria-label of the form "Level 3 progress — 42 / 100 XP" lets screen readers announce both the level and the XP readout in one phrase.
  • The leading pill and trailing readout are aria-hidden="true" for non-visual consumers since the same information is already on the progressbar's aria-label.
  • Motion respects prefers-reduced-motion — the fill renders at its final width instantly when the user opts out.

Credits

  • Extracted from: AlgoFlashcards (src/platform/ui/XPBar.tsx). Generalized the source's value-only API into level + xpInLevel + xpForNextLevel, added forwardRef + className + ...props, added the level pill + XP readout, surfaced formatXP for custom readouts, and wired usePrefersReducedMotion for accessible motion.