Box

Generic container chrome for arbitrary content, with no content slots of its own.

Arbitrary content, no header, title, or footer slots.

Usage

import { Box } from '@epilot/spark-ui/box'
<Box variant="surface">
  <p>Arbitrary content, no header, title, or footer slots.</p>
  <Button size="small">Action</Button>
</Box>

Box is the same chrome recipe Card uses (variant, color, radius), with none of Card's header/icon/title/description/footer slots. Reach for it when the content wrapped is arbitrary, rather than a title+description shape. Use Box for arbitrary content that just needs chrome, Card for the header/icon/title/description/footer slots, Accordion when the content collapses, and PageContainer for page width and gap, which is not chrome at all.

The chrome token family is named --spark-card-* for historical reasons. Box reads the exact same tokens and the same app-level <Theme cardVariant cardColor> default as Card, so both stay in lockstep with a single knob.

Examples

Variants

Box takes a self-scoped variant (soft, surface, outline, ghost, solid) and color (neutral, accent), identical to Card's, since they share one chrome recipe.

color=neutral

soft

surface

outline

ghost

solid

color=accent

soft

surface

outline

ghost

solid

Padding

padding (none, sm, md, lg) controls inset on all sides. md (default) follows the variant's own inset: chromed variants pad, ghost sits flush. none strips padding entirely, useful for a flush, clipped frame around content that provides its own inset (an image, a chart).

none

sm

md

lg

Radius

none

md

2xl

full

Interactive

Pass render with an <a href/> or <button/> to make the whole box the click target: it gains a hover tint, focus ring, and disabled styles. Don't nest other interactive controls inside an interactive box.

API Reference

PropTypeDefaultDescription
variant'soft' | 'surface' | 'outline' | 'ghost' | 'solid'knob/softContainer chrome, scoped to the box (never cascades into child controls). Unset follows the app-level data-card-variant.
color'neutral' | 'accent''neutral'Chrome palette. neutral tracks the app theme's neutral color; accent tints the chrome with the brand accent.
radius'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full''2xl'Corner radius. Each step maps to the matching Tailwind rounded-* utility, so it still scales with the page-wide Roundness knob.
padding'none' | 'sm' | 'md' | 'lg''md'Inset on all sides. md follows the variant's own default inset; none strips it entirely.
renderReactElementBase UI polymorphism. Pass <a href/> or <button/> to make the box interactive (hover tint, focus ring, disabled styles).

Set app-wide defaults with the Theme provider's cardVariant / cardColor props, the same knob Card reads; a per-box prop overrides it.

Accessibility

  • An interactive Box (render={<a>} or render={<button>}) is one click target. Don't nest other interactive controls inside it.
  • render={<button>} needs its own type="button" (or type="submit" where relevant); Box doesn't set one for you.
  • Chrome never cascades into child controls: a Box styled variant="outline" doesn't outline the buttons inside it.

On this page