Customization
Soft UI components are built to be flexible while maintaining design consistency. This guide covers the recommended approaches for customizing components.Semantic Props Pattern
The primary way to customize components is through semantic props:variant, size, tone, and component-specific props.
Variant Prop
Controls the visual style of the component:Size Prop
Controls the dimensions and spacing:Tone Prop
Overrides color for certain variants. Supports both feedback and decorative tones:Class Variance Authority (CVA)
All Soft UI components use CVA for managing variants. This provides type-safe variant composition.Real Example from Button Component
Frompackages/react/src/components/button.tsx:56-97:
Creating Custom Variants
You can extend component variants by wrapping them:The className Prop
TheclassName prop is additive only and should be used for:
- Layout positioning (
self-start,flex-1) - Spacing from parent (
mt-4,mb-8) - Width constraints (
w-full,max-w-xs)
className to:
- Change component internals (height, padding, typography)
- Override variant styles
- Reposition slots (icons, labels)
Correct Usage
Incorrect Usage
The unsafeClassName Escape Hatch
For intentional structural overrides, hardened components provideunsafeClassName.
Use this only when:
- You need to override component internals
- You’ve reviewed the design impact
- Semantic props cannot achieve your goal
Components with unsafeClassName
Button,IconButtonButtonGroup,ButtonGroupItemToggleButton,ToggleGroup,ToggleGroupItemSlider*,AdjustmentSliderInput,Textarea,InputGroup,NumberFieldCheckboxControl,RadioControl,SwitchControlTabs*,SegmentedControl*Select.Trigger,Autocomplete.Root,Combobox.RootChip,ChipGroup,Badge,Avatar,AvatarGroupField,Filter
Example Usage
Frompackages/react/src/components/button.tsx:136-174:
When to Use unsafeClassName
Token-Driven Customization
All components use CSS variables from the design token system.Available Token Categories
- Colors:
--color-actions-*,--color-content-*,--color-surface-*,--color-border-* - Spacing:
--space-{2,4,8,10,12,16,18,20,24,28,32,36,40,...} - Typography:
--font-size-*,--line-height-*,--font-weight-* - Radii:
--radius-{4,6,8,10,12,max} - Focus:
--color-utility-focus-inner,--color-utility-focus-outer
Using Tokens in Custom Styles
Utility Classes
Frompackages/tokens/src/utilities.css:54-184, typography utilities are available:
Extending Components
Wrapper Pattern
Create a wrapper component to add custom behavior:Composition Pattern
Compose multiple components for complex UIs:Component Integrity Rules
To prevent layout issues and maintain consistency:- Prefer semantic props over
className - Treat
classNameas additive (spacing, layout placement) - Use
unsafeClassNameonly for intentional structural overrides - Never change slot styling (button labels/icons, slider values, segment indicators)
- Use wrapper/container classes for placement instead of styling component internals
Allowed vs Forbidden Overrides
| Component Type | Allowed | Forbidden |
|---|---|---|
| Buttons | variant, size, tone, icon/label props | Forcing h-*, w-*, px-*, text-* via className |
| Inputs | variant, size, prefix/suffix props | Overriding heights/paddings/typography |
| Sliders | variant, size, min/max/step props | Repositioning thumb/value text |
| Controls | checked/disabled/state props | Changing control dimensions |
Best Practices
- Always check semantic props first before reaching for
classNameorunsafeClassName - Use design tokens for consistent spacing and colors
- Wrap components for reusable customizations
- Document intentional overrides when using
unsafeClassName - Test across variants and sizes when extending components