Files
sigpro-ui/docs/components/radio.md
2026-04-06 03:19:15 +02:00

409 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Radio
Radio button component with label, tooltip support, and reactive group selection. All radios in the same group share a common `name` attribute for proper HTML semantics.
## Tag
`Radio`
## Props
| Prop | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| `label` | `string` | `-` | Label text for the radio button |
| `value` | `string \| Signal<string>` | `-` | Selected value signal for the group |
| `inputValue` | `string` | `-` | Value of this radio button |
| `name` | `string` | `-` | Group name (all radios in group should share this) |
| `tooltip` | `string` | `-` | Tooltip text on hover |
| `disabled` | `boolean \| Signal<boolean>` | `false` | Disabled state |
| `class` | `string` | `''` | Additional CSS classes (DaisyUI + Tailwind) |
| `onclick` | `function` | `-` | Click event handler |
## Styling
Radio supports all **daisyUI Radio classes**:
| Category | Keywords | Description |
| :--- | :--- | :--- |
| Color | `radio-primary`, `radio-secondary`, `radio-accent`, `radio-info`, `radio-success`, `radio-warning`, `radio-error` | Radio color variants |
| Size | `radio-xs`, `radio-sm`, `radio-md`, `radio-lg` | Radio scale |
> For further details, check the [daisyUI Radio Documentation](https://daisyui.com/components/radio) Full reference for CSS classes.
## Live Examples
### Basic Radio Group
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
<div class="card-body">
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
<div id="demo-basic" class="bg-base-100 p-6 rounded-xl border border-base-300 flex flex-col gap-3"></div>
</div>
</div>
```javascript
const BasicDemo = () => {
const selected = $('option1');
return Div({ class: 'flex flex-col gap-3' }, [
Radio({
label: 'Option 1',
name: 'basic-group',
value: selected,
inputValue: 'option1',
onclick: () => selected('option1')
}),
Radio({
label: 'Option 2',
name: 'basic-group',
value: selected,
inputValue: 'option2',
onclick: () => selected('option2')
}),
Radio({
label: 'Option 3',
name: 'basic-group',
value: selected,
inputValue: 'option3',
onclick: () => selected('option3')
}),
Div({ class: 'mt-2 text-sm opacity-70' }, () => `Selected: ${selected()}`)
]);
};
Mount(BasicDemo, '#demo-basic');
```
### With Tooltip
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
<div class="card-body">
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
<div id="demo-tooltip" class="bg-base-100 p-6 rounded-xl border border-base-300 flex flex-col gap-3"></div>
</div>
</div>
```javascript
const TooltipDemo = () => {
const selected = $('light');
return Div({ class: 'flex flex-col gap-3' }, [
Radio({
label: 'Light mode',
name: 'theme-group',
value: selected,
inputValue: 'light',
tooltip: 'Light theme with white background',
onclick: () => selected('light')
}),
Radio({
label: 'Dark mode',
name: 'theme-group',
value: selected,
inputValue: 'dark',
tooltip: 'Dark theme with black background',
onclick: () => selected('dark')
})
]);
};
Mount(TooltipDemo, '#demo-tooltip');
```
### Disabled State
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
<div class="card-body">
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
<div id="demo-disabled" class="bg-base-100 p-6 rounded-xl border border-base-300 flex flex-col gap-3"></div>
</div>
</div>
```javascript
const DisabledDemo = () => {
const selected = $('enabled');
return Div({ class: 'flex flex-col gap-3' }, [
Radio({
label: 'Enabled option',
name: 'disabled-group',
value: selected,
inputValue: 'enabled',
onclick: () => selected('enabled')
}),
Radio({
label: 'Disabled option (cannot select)',
name: 'disabled-group',
value: selected,
inputValue: 'disabled',
disabled: true,
onclick: () => selected('disabled')
})
]);
};
Mount(DisabledDemo, '#demo-disabled');
```
### Reactive Preview
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
<div class="card-body">
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
<div id="demo-reactive" class="bg-base-100 p-6 rounded-xl border border-base-300"></div>
</div>
</div>
```javascript
const ReactiveDemo = () => {
const size = $('medium');
const color = $('blue');
const sizes = [
{ value: 'small', label: 'Small' },
{ value: 'medium', label: 'Medium' },
{ value: 'large', label: 'Large' }
];
const colors = [
{ value: 'blue', label: 'Blue' },
{ value: 'green', label: 'Green' },
{ value: 'red', label: 'Red' }
];
return Div({ class: 'flex flex-col gap-4' }, [
Div({ class: 'text-sm font-bold' }, 'Select size'),
Div({ class: 'flex gap-4' }, sizes.map(s =>
Radio({
label: s.label,
name: 'size-group',
value: size,
inputValue: s.value,
onclick: () => size(s.value)
})
)),
Div({ class: 'text-sm font-bold mt-2' }, 'Select color'),
Div({ class: 'flex gap-4' }, colors.map(c =>
Radio({
label: c.label,
name: 'color-group',
value: color,
inputValue: c.value,
onclick: () => color(c.value)
})
)),
Div({
class: 'mt-4 p-4 rounded-lg text-center transition-all',
style: () => {
const sizeMap = { small: 'text-sm', medium: 'text-base', large: 'text-lg' };
const colorMap = { blue: '#3b82f6', green: '#10b981', red: '#ef4444' };
return `background-color: ${colorMap[color()]}; color: white; ${sizeMap[size()]}`;
}
}, () => `${size()} ${color()} preview`)
]);
};
Mount(ReactiveDemo, '#demo-reactive');
```
### Payment Method Selection
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
<div class="card-body">
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
<div id="demo-payment" class="bg-base-100 p-6 rounded-xl border border-base-300"></div>
</div>
</div>
```javascript
const PaymentDemo = () => {
const method = $('credit');
return Div({ class: 'flex flex-col gap-4' }, [
Div({ class: 'text-sm font-bold' }, 'Payment method'),
Div({ class: 'flex flex-col gap-3' }, [
Radio({
label: '💳 Credit Card',
name: 'payment-group',
value: method,
inputValue: 'credit',
onclick: () => method('credit')
}),
Radio({
label: '🏦 Bank Transfer',
name: 'payment-group',
value: method,
inputValue: 'bank',
onclick: () => method('bank')
}),
Radio({
label: '📱 Digital Wallet',
name: 'payment-group',
value: method,
inputValue: 'wallet',
onclick: () => method('wallet')
})
]),
Div({ class: 'alert alert-info mt-2' }, () => {
const messages = {
credit: 'You selected Credit Card. Enter your card details.',
bank: 'You selected Bank Transfer. Use the provided account number.',
wallet: 'You selected Digital Wallet. Scan the QR code to pay.'
};
return messages[method()];
})
]);
};
Mount(PaymentDemo, '#demo-payment');
```
### All Variants
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
<div class="card-body">
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
<div id="demo-variants" class="bg-base-100 p-6 rounded-xl border border-base-300 flex flex-col gap-4"></div>
</div>
</div>
```javascript
const VariantsDemo = () => {
const primary = $('primary1');
const secondary = $('secondary1');
const accent = $('accent1');
return Div({ class: 'flex flex-col gap-4' }, [
Div({ class: 'card bg-base-200 p-4' }, [
Div({ class: 'text-sm font-bold mb-2' }, 'Primary variant'),
Div({ class: 'flex gap-4' }, [
Radio({
label: 'Option A',
name: 'primary-group',
value: primary,
inputValue: 'primary1',
class: 'radio-primary',
onclick: () => primary('primary1')
}),
Radio({
label: 'Option B',
name: 'primary-group',
value: primary,
inputValue: 'primary2',
class: 'radio-primary',
onclick: () => primary('primary2')
})
])
]),
Div({ class: 'card bg-base-200 p-4' }, [
Div({ class: 'text-sm font-bold mb-2' }, 'Secondary variant'),
Div({ class: 'flex gap-4' }, [
Radio({
label: 'Option A',
name: 'secondary-group',
value: secondary,
inputValue: 'secondary1',
class: 'radio-secondary',
onclick: () => secondary('secondary1')
}),
Radio({
label: 'Option B',
name: 'secondary-group',
value: secondary,
inputValue: 'secondary2',
class: 'radio-secondary',
onclick: () => secondary('secondary2')
})
])
]),
Div({ class: 'card bg-base-200 p-4' }, [
Div({ class: 'text-sm font-bold mb-2' }, 'Accent variant'),
Div({ class: 'flex gap-4' }, [
Radio({
label: 'Option A',
name: 'accent-group',
value: accent,
inputValue: 'accent1',
class: 'radio-accent',
onclick: () => accent('accent1')
}),
Radio({
label: 'Option B',
name: 'accent-group',
value: accent,
inputValue: 'accent2',
class: 'radio-accent',
onclick: () => accent('accent2')
})
])
])
]);
};
Mount(VariantsDemo, '#demo-variants');
```
### Dynamic Options
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
<div class="card-body">
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
<div id="demo-dynamic" class="bg-base-100 p-6 rounded-xl border border-base-300"></div>
</div>
</div>
```javascript
const DynamicDemo = () => {
const category = $('cars');
const selected = $('');
const options = {
cars: [
{ value: 'sedan', label: 'Sedan' },
{ value: 'suv', label: 'SUV' },
{ value: 'sports', label: 'Sports' }
],
colors: [
{ value: 'red', label: 'Red' },
{ value: 'blue', label: 'Blue' },
{ value: 'black', label: 'Black' }
]
};
return Div({ class: 'flex flex-col gap-4' }, [
Div({ class: 'flex gap-4' }, [
Radio({
label: 'Cars',
name: 'category-group',
value: category,
inputValue: 'cars',
onclick: () => {
category('cars');
selected('');
}
}),
Radio({
label: 'Colors',
name: 'category-group',
value: category,
inputValue: 'colors',
onclick: () => {
category('colors');
selected('');
}
})
]),
Div({ class: 'divider my-1' }),
Div({ class: 'text-sm font-bold' }, () => `Select ${category()}`),
Div({ class: 'flex flex-col gap-2' }, () =>
options[category()].map(opt =>
Radio({
label: opt.label,
name: 'dynamic-option-group',
value: selected,
inputValue: opt.value,
onclick: () => selected(opt.value)
})
)
),
() => selected()
? Div({ class: 'alert alert-success mt-2' }, () => `Selected ${category()}: ${selected()}`)
: null
]);
};
Mount(DynamicDemo, '#demo-dynamic');
```