Box
A flexible, polymorphic container component that serves as the foundation for layout and spacing in the Lufa Design System.
Overview​
Use Box when you need…
- A universal layout primitive with utility-based spacing props (
padding,margin) - Semantic HTML elements via the polymorphic
asprop (section,article,header, etc.) - Quick prototyping with background colors, borders, and border radius
- A performance-optimized container (uses CSS classes, not inline styles)
- Token-based design values that automatically adapt to light and dark themes
Anatomy​
The Box component is a single container element with configurable spacing and visual properties.
- Container: Single element (default
div, customizable viaasprop) - Padding: Inner spacing between border and content (supports all directions)
- Margin: Outer spacing between Box and adjacent elements (supports all directions)
- Border: Optional border with customizable width, color, and radius
- Background: Optional semantic background color from design tokens
- Display: CSS display property (
block,flex,grid, and more)
Usage​
import { Box } from '@grasdouble/lufa_design-system';
export function BasicBox() {
return (
<>
<Box padding="default">Content</Box>
<Box padding="comfortable" background="surface" borderRadius="medium" borderWidth="thin" borderColor="default">
Card content
</Box>
</>
);
}
import { Box } from '@grasdouble/lufa_design-system';
export function SemanticSection() {
return (
<Box as="section" padding="spacious" aria-labelledby="section-title">
<h2 id="section-title">Section title</h2>
<Box display="flex" style={{ gap: '16px' }}>
<Box>Item 1</Box>
<Box>Item 2</Box>
</Box>
</Box>
);
}
Props​
| Prop | Type | Default | Description |
|---|---|---|---|
as | 'div' | 'section' | 'article' | 'header' | 'footer' | 'main' | 'nav' | 'aside' | 'div' | HTML element to render |
padding | 'none' | 'tight' | 'compact' | 'default' | 'comfortable' | 'spacious' | undefined | Padding on all sides |
paddingX | 'none' | 'tight' | 'compact' | 'default' | 'comfortable' | 'spacious' | undefined | Horizontal padding (left + right) |
paddingY | 'none' | 'tight' | 'compact' | 'default' | 'comfortable' | 'spacious' | undefined | Vertical padding (top + bottom) |
paddingTop | 'none' | 'tight' | 'compact' | 'default' | 'comfortable' | 'spacious' | undefined | Padding top only |
paddingRight | 'none' | 'tight' | 'compact' | 'default' | 'comfortable' | 'spacious' | undefined | Padding right only |
paddingBottom | 'none' | 'tight' | 'compact' | 'default' | 'comfortable' | 'spacious' | undefined | Padding bottom only |
paddingLeft | 'none' | 'tight' | 'compact' | 'default' | 'comfortable' | 'spacious' | undefined | Padding left only |
margin | 'none' | 'tight' | 'compact' | 'default' | 'comfortable' | 'spacious' | undefined | Margin on all sides |
marginX | 'none' | 'tight' | 'compact' | 'default' | 'comfortable' | 'spacious' | undefined | Horizontal margin (left + right) |
marginY | 'none' | 'tight' | 'compact' | 'default' | 'comfortable' | 'spacious' | undefined | Vertical margin (top + bottom) |
marginTop | 'none' | 'tight' | 'compact' | 'default' | 'comfortable' | 'spacious' | undefined | Margin top only |
marginRight | 'none' | 'tight' | 'compact' | 'default' | 'comfortable' | 'spacious' | undefined | Margin right only |
marginBottom | 'none' | 'tight' | 'compact' | 'default' | 'comfortable' | 'spacious' | undefined | Margin bottom only |
marginLeft | 'none' | 'tight' | 'compact' | 'default' | 'comfortable' | 'spacious' | undefined | Margin left only |
background | 'page' | 'surface' | 'success' | 'error' | 'warning' | 'info' | 'overlay' | 'on-primary' | 'on-secondary' | 'on-success' | 'on-error' | 'on-warning' | 'on-info' | undefined | Background color using semantic tokens |
borderRadius | 'none' | 'small' | 'default' | 'medium' | 'large' | 'full' | undefined | Border radius (rounded corners) |
borderWidth | 'none' | 'thin' | 'medium' | 'thick' | undefined | Border width on all sides |
borderColor | 'default' | 'strong' | 'success' | 'error' | 'warning' | 'info' | undefined | Border color using semantic tokens |
display | 'block' | 'inline-block' | 'flex' | 'inline-flex' | 'grid' | 'none' | undefined | CSS display property |
className | string | undefined | Additional CSS classes |
children | ReactNode | undefined | Child elements to render inside the Box |
Also supports all standard HTML attributes for the underlying element (for example id, role, aria-*, data-*, style, and event handlers).
Spacing prop priority: individual sides override axis props, which override all-sides props.
import { Box } from '@grasdouble/lufa_design-system';
export function SpacingPriority() {
return (
<Box padding="default" paddingX="spacious" paddingTop="tight">
Content
</Box>
);
}
Accessibility​
Box is a non-interactive container by default. Use semantic elements and ARIA attributes when they add meaning, and avoid making containers focusable unless required.
import { Box } from '@grasdouble/lufa_design-system';
export function LandmarkExample() {
return (
<Box as="nav" aria-label="Primary">
<a href="/">Home</a>
<a href="/about">About</a>
</Box>
);
}
Theming & Tokens​
Box props map to design tokens that stay consistent across themes.
- Spacing tokens:
none(0px),tight(4px),compact(8px),default(16px),comfortable(24px),spacious(32px) - Background tokens:
page,surface,success,error,warning,info,overlay,on-primary,on-secondary,on-success,on-error,on-warning,on-info - Border tokens: radius
none,small,default,medium,large,full; widthnone,thin,medium,thick; colordefault,strong,success,error,warning,info
All semantic background tokens are tested in light and dark themes to meet WCAG 2.1 AA contrast requirements for text.
Do / Don’t​
- Use semantic HTML via the
asprop for landmarks and sections - Pair
borderWidthwithborderColorwhen you want a visible border - Use spacing tokens consistently to keep visual rhythm
- Prefer
Boxover custom divs for consistent token usage
- Use
Boxfor everything when plain semantic HTML is enough - Set
borderWidthwithoutborderColor - Hardcode spacing values in
stylewhen tokens are available - Make non-interactive Boxes focusable without a reason
Related Components​
- Stack - Vertical or horizontal spacing layout (builds on Box with
display="flex"and gap) - Grid - Grid layout primitive (builds on Box with
display="grid") - Flex - Flexbox layout primitive (builds on Box with
display="flex") - Container - Max-width centered container (builds on Box with responsive widths)
- Text - Typography component (can be composed with Box for styled text blocks)
- Divider - Visual separator (can be used within Box for content sections)