All stateful components in @bitcode/ui follow the ADR-007 controlled/uncontrolled pattern. You can use components in two modes:
- Controlled — you manage the state externally
- Uncontrolled — the component manages its own state
Every stateful prop has three pieces:
| Prop | Purpose |
|---|---|
value / open / checked |
Controlled — you own the state |
defaultValue / defaultOpen / defaultChecked |
Uncontrolled — initial value only |
onValueChange / onOpenChange / onCheckedChange |
Callback — fires on every change |
// Component manages its own state. You just read changes.
<BcInput
name="email"
defaultValue="john@example.com"
onValueChange={(value, meta) => console.log(value)}
/>const [email, setEmail] = useState('');
<BcInput
name="email"
value={email}
onValueChange={(value, meta) => setEmail(value)}
/>If you're using the old initialX props, migrate to defaultX:
// ❌ Old (deprecated)
<BcDataTable initialSort={[{ field: 'name', direction: 'asc' }]} />
// ✅ New
<BcDataTable defaultSortModel={[{ field: 'name', direction: 'asc' }]} />| State | Controlled | Uncontrolled | Callback |
|---|---|---|---|
| value | value |
defaultValue |
onValueChange |
| open | open |
defaultOpen |
onOpenChange |
| checked | checked |
defaultChecked |
onCheckedChange |
| selected keys | selectedKeys |
defaultSelectedKeys |
onSelectionChange |
| active key | activeKey |
defaultActiveKey |
onActiveKeyChange |
| expanded keys | expandedKeys |
defaultExpandedKeys |
onExpandedChange |
| sort model | sortModel |
defaultSortModel |
onSortModelChange |
| filter model | filterModel |
defaultFilterModel |
onFilterModelChange |
| column state | columnState |
defaultColumnState |
onColumnStateChange |
- Never mutate a controlled prop internally. The component treats
value/open/checkedas read-only. initialXis deprecated. UsedefaultXinstead. Legacy aliases exist for backward compatibility.- Callback meta always includes reason + source. This lets you distinguish user input from programmatic changes.