Box
Polymorphic container with token-driven padding, background, border, radius, and shadow. The most common reach-for primitive when wrapping content with semantic styling.
Dependencies
Source Code
import type { VariantProps } from 'cva';
import { Slot } from '@/components/slot';
import { cn, cva } from '@/lib/utils/classnames';
const boxStyle = cva({
base: '',
variants: {
padding: {
none: 'p-0',
xs: 'p-1',
sm: 'p-2',
md: 'p-4',
lg: 'p-6',
xl: 'p-8',
'2xl': 'p-12',
},
paddingX: {
none: 'px-0',
xs: 'px-1',
sm: 'px-2',
md: 'px-4',
lg: 'px-6',
xl: 'px-8',
'2xl': 'px-12',
},
paddingY: {
none: 'py-0',
xs: 'py-1',
sm: 'py-2',
md: 'py-4',
lg: 'py-6',
xl: 'py-8',
'2xl': 'py-12',
},
bg: {
none: '',
background: 'bg-background',
'background-secondary': 'bg-background-secondary',
'surface-sunken': 'bg-surface-sunken',
'surface-default': 'bg-surface-default',
'surface-raised': 'bg-surface-raised',
'surface-overlay': 'bg-surface-overlay',
},
border: {
true: 'border border-border',
false: '',
subtle: 'border border-divider',
},
radius: {
none: 'rounded-none',
xs: 'rounded-xs',
sm: 'rounded-sm',
md: 'rounded-md',
lg: 'rounded-lg',
xl: 'rounded-xl',
'2xl': 'rounded-2xl',
full: 'rounded-full',
},
shadow: {
none: '',
raised: 'shadow-raised',
overlay: 'shadow-overlay',
},
},
});
interface BoxProps
extends React.ComponentPropsWithRef<'div'>,
VariantProps<typeof boxStyle> {
asChild?: boolean;
}
const Box = ({
ref,
className,
padding,
paddingX,
paddingY,
bg,
border,
radius,
shadow,
asChild,
...rest
}: BoxProps) => {
const Comp = asChild ? Slot : 'div';
return (
<Comp
ref={ref}
className={cn(
boxStyle({ padding, paddingX, paddingY, bg, border, radius, shadow }),
className
)}
{...rest}
/>
);
};
export type { BoxProps };
export { Box }; API
| Prop | Default | Type | Description |
|---|---|---|---|
padding | - | 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | Padding on all sides. |
paddingX | - | same as padding | Overrides the x-axis of padding. `<Box padding="md" paddingX="sm" />` emits `p-4 px-2`; the longhand sub-axis wins. |
paddingY | - | same as padding | Overrides the y-axis of padding. Same precedence as paddingX. |
bg | - | 'none' | 'background' | 'background-secondary' | 'surface-sunken' | 'surface-default' | 'surface-raised' | 'surface-overlay' | Background using semantic theme tokens. Surface tokens auto-follow the active scheme. |
border | - | boolean | 'subtle' | Border using --color-border (true) or --color-divider (subtle). |
radius | - | 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'full' | Border radius matching the global --radius-* scale. |
shadow | - | 'none' | 'raised' | 'overlay' | Paired elevation shadows from elevation.css. Use with bg=surface-raised or bg=surface-overlay for coherent depth. |
asChild | - | boolean | Render as the child element via Slot. |
Examples
Default
A bare <Box> is a <div> with no styling — useful as a polymorphic stub.
With background and padding
Use semantic bg tokens so the box follows whichever theme scheme is active.
Elevated card
Pair bg='surface-raised' with shadow='raised' and radius='md' for a standard card.
Previous
Badge
Next
Breadcrumb