Interactive demo of button card field
Overview
The button card field presents options as rich, card-style components. Each option can include an icon, title, description, and optional badge. Ideal for plan selection, feature comparison, or any choice where visual hierarchy helps users decide.
Usage
Basic Button Card
import { FormBuilder } from '@saastro/forms';
const config = FormBuilder.create('form')
.addField('plan', (f) =>
f
.type('button-card')
.label('Select a Plan')
.buttonCardOptions([
{
value: 'free',
title: 'Free',
description: 'Perfect for getting started',
icon: '🆓',
},
{
value: 'pro',
title: 'Pro',
description: 'For growing teams',
icon: '⭐',
badge: 'Popular',
},
{
value: 'enterprise',
title: 'Enterprise',
description: 'Custom solutions',
icon: '🏢',
},
])
.required('Please select a plan'),
)
.addStep('main', ['plan'])
.build();
Multi-select Cards
.addField('features', (f) =>
f.type('button-card')
.label('Select Features')
.buttonCardOptions([
{ value: 'analytics', title: 'Analytics', description: 'Track metrics', icon: '📊' },
{ value: 'api', title: 'API Access', description: 'REST & GraphQL', icon: '🔌' },
{ value: 'support', title: 'Priority Support', description: '24/7 help', icon: '💬' },
])
// Enable multi-select mode
.value([])
.optional()
)
JSON Configuration
{
"type": "button-card",
"label": "Select a Plan",
"options": [
{
"value": "free",
"title": "Free",
"description": "Perfect for getting started",
"icon": "🆓"
},
{
"value": "pro",
"title": "Pro",
"description": "For growing teams",
"icon": "⭐",
"badge": "Popular"
}
],
"schema": { "required": true }
}
Props
| Prop | Type | Default | Description |
|---|---|---|---|
type | 'button-card' | - | Field type (required) |
label | string | - | Group label |
helperText | string | - | Help text below field |
options | ButtonCardOption[] | - | Array of card options |
value | string | string[] | - | Selected value(s) |
optionsClassName | string | - | CSS classes for cards container grid |
columns | Partial<Record<Breakpoint, number>> | - | Grid columns by breakpoint |
disabled | boolean | function | ConditionGroup | false | Disable all cards |
hidden | boolean | function | ConditionGroup | Responsive | false | Hide the field |
ButtonCardOption Object
| Property | Type | Description |
|---|---|---|
value | string | Selection value |
title | string | Card title |
description | string | Card description |
icon | string | ReactNode | Icon (emoji or component) |
badge | string | Optional badge text |
disabled | boolean | Disable this card |
Validation
Required Selection
.addField('tier', (f) =>
f.type('button-card')
.label('Select Tier')
.buttonCardOptions([...])
.required('Please select a tier')
)
Styling
Custom Classes
.addField('plan', (f) =>
f.type('button-card')
.label('Select a Plan')
.buttonCardOptions([...])
.required()
.classNames({
wrapper: 'bg-muted/30 p-4 rounded-lg',
label: 'text-lg font-semibold mb-3',
error: 'text-destructive text-sm',
})
)
Cards Layout with optionsClassName
Control card arrangement:
{
"type": "button-card",
"label": "Select Plan",
"optionsClassName": "grid grid-cols-1 md:grid-cols-3 gap-4",
"options": [...]
}
Responsive Layout
.addField('plan', (f) =>
f.type('button-card')
.label('Select a Plan')
.buttonCardOptions([...])
.columns({ default: 12, md: 8 })
)
JSON Styling
{
"type": "button-card",
"label": "Select Plan",
"wrapper_className": "bg-muted/30 p-6 rounded-xl",
"label_className": "text-xl font-bold",
"optionsClassName": "grid grid-cols-1 md:grid-cols-3 gap-6",
"columns": { "default": 12 }
}
Related Fields
- Radio - Simple radio options
- Button Radio - Compact button selection
- Select - Dropdown selection
Accessibility
- Keyboard navigation between cards
- ARIA roles for selectable cards
- Focus visible states
- Screen reader announcements