Skip to content
Open
33 changes: 32 additions & 1 deletion docs/content/docs/2.components/checkbox-group.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,9 @@ You can also pass an array of objects with the following properties:
- `description?: string`{lang="ts-type"}
- [`value?: string`{lang="ts-type"}](#value-key)
- `disabled?: boolean`{lang="ts-type"}
- `icon?: string`{lang="ts-type"}
- `class?: any`{lang="ts-type"}
- `ui?: { item?: ClassNameValue, container?: ClassNameValue, base?: ClassNameValue, 'indicator'?: ClassNameValue, icon?: ClassNameValue, wrapper?: ClassNameValue, label?: ClassNameValue, description?: ClassNameValue }`{lang="ts-type"}
- `ui?: { item?: ClassNameValue, container?: ClassNameValue, base?: ClassNameValue, 'indicator'?: ClassNameValue, icon?: ClassNameValue, wrapper?: ClassNameValue, label?: ClassNameValue, leadingIcon?: ClassNameValue, description?: ClassNameValue }`{lang="ts-type"}

::component-code
---
Expand Down Expand Up @@ -129,6 +130,36 @@ props:
---
::

### Icon

Use the `icon` property in the items to display an icon next to the label.

::component-code
---
ignore:
- modelValue
- items
external:
- items
- modelValue
externalTypes:
- CheckboxGroupItem[]
props:
modelValue:
- 'system'
items:
- label: 'System'
icon: 'i-lucide-monitor'
value: 'system'
- label: 'Light'
icon: 'i-lucide-sun'
value: 'light'
- label: 'Dark'
icon: 'i-lucide-moon'
value: 'dark'
---
::

### Legend

Use the `legend` prop to set the legend of the CheckboxGroup.
Expand Down
14 changes: 14 additions & 0 deletions docs/content/docs/2.components/checkbox.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,20 @@ You can customize this icon globally in your `vite.config.ts` under `ui.icons.ch
:::
::

### Leading Icon

Use the `leading-icon` prop to display an icon next to the label of the Checkbox.

::component-code
---
ignore:
- label
props:
leadingIcon: 'i-lucide-tag'
label: Check me
---
::

### Color

Use the `color` prop to change the color of the Checkbox.
Expand Down
32 changes: 31 additions & 1 deletion docs/content/docs/2.components/radio-group.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,9 @@ You can also pass an array of objects with the following properties:
- `description?: string`{lang="ts-type"}
- [`value?: string`{lang="ts-type"}](#value-key)
- `disabled?: boolean`{lang="ts-type"}
- `icon?: string`{lang="ts-type"}
- `class?: any`{lang="ts-type"}
- `ui?: { item?: ClassNameValue, container?: ClassNameValue, base?: ClassNameValue, 'indicator'?: ClassNameValue, wrapper?: ClassNameValue, label?: ClassNameValue, description?: ClassNameValue }`{lang="ts-type"}
- `ui?: { item?: ClassNameValue, container?: ClassNameValue, base?: ClassNameValue, 'indicator'?: ClassNameValue, wrapper?: ClassNameValue, label?: ClassNameValue, leadingIcon?: ClassNameValue, description?: ClassNameValue }`{lang="ts-type"}

::component-code
---
Expand Down Expand Up @@ -124,6 +125,35 @@ props:
---
::

### Icon

Use the `icon` property in the items to display an icon next to the label.

::component-code
---
ignore:
- modelValue
- items
external:
- items
- modelValue
externalTypes:
- RadioGroupItem[]
props:
modelValue: 'system'
items:
- label: 'System'
icon: 'i-lucide-monitor'
value: 'system'
- label: 'Light'
icon: 'i-lucide-sun'
value: 'light'
- label: 'Dark'
icon: 'i-lucide-moon'
value: 'dark'
---
::

### Legend

Use the `legend` prop to set the legend of the RadioGroup.
Expand Down
29 changes: 29 additions & 0 deletions playgrounds/nuxt/app/pages/components/checkbox-group.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,19 @@ const itemsWithDescription = [
{ value: '2', label: 'Option 2', description: 'Description 2' },
{ value: '3', label: 'Option 3', description: 'Description 3' }
]
const itemsWithIcon = [
{ value: '1', label: 'System', icon: 'i-lucide-monitor' },
{ value: '2', label: 'Light', icon: 'i-lucide-sun' },
{ value: '3', label: 'Dark', icon: 'i-lucide-moon' }
]
const viewItems = [
{ value: 'table', label: 'Table', icon: 'i-lucide-table' },
{ value: 'board', label: 'Board', icon: 'i-lucide-kanban' },
{ value: 'calendar', label: 'Calendar', icon: 'i-lucide-calendar' },
{ value: 'list', label: 'List', icon: 'i-lucide-list' },
{ value: 'gallery', label: 'Gallery', icon: 'i-lucide-images' },
{ value: 'map', label: 'Map', icon: 'i-lucide-map' }
]
</script>

<template>
Expand All @@ -47,6 +60,7 @@ const itemsWithDescription = [
<UCheckboxGroup :items="items" :default-value="['1']" :orientation="orientation" v-bind="props" />
<UCheckboxGroup :items="itemsLiteral" :default-value="['Option 1']" :orientation="orientation" v-bind="props" />
<UCheckboxGroup :items="itemsWithDescription" :orientation="orientation" v-bind="props" />
<UCheckboxGroup :items="itemsWithIcon" :orientation="orientation" v-bind="props" />
<UCheckboxGroup :items="items" disabled :orientation="orientation" v-bind="props" />
<UCheckboxGroup :items="items" legend="Legend" :orientation="orientation" v-bind="props" />
<UCheckboxGroup :items="items" legend="Legend" required :orientation="orientation" v-bind="props" />
Expand All @@ -63,4 +77,19 @@ const itemsWithDescription = [
</template>
</UCheckboxGroup>
</Matrix>

<!-- Icon-on-top card grid built on the per-item `icon`, using only `ui` overrides -->
<div class="p-4 border-t border-default">
<UCheckboxGroup
:default-value="['table']"
variant="card"
indicator="hidden"
:items="viewItems"
:ui="{
fieldset: 'grid grid-cols-3 gap-2 w-96',
label: 'flex flex-col items-center gap-1.5',
leadingIcon: 'size-6 me-0'
}"
/>
</div>
</template>
1 change: 1 addition & 0 deletions playgrounds/nuxt/app/pages/components/checkbox.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const value = ref(true)
<UCheckbox label="Default value" v-bind="props" :default-value="true" />
<UCheckbox label="Indeterminate" v-bind="props" default-value="indeterminate" />
<UCheckbox label="Icon" icon="i-lucide-heart" v-bind="props" :model-value="true" />
<UCheckbox label="Leading icon" leading-icon="i-lucide-tag" v-bind="props" />
<UCheckbox label="Required" v-bind="props" required />
<UCheckbox label="Disabled" v-bind="props" disabled />
<UCheckbox label="Description" description="This is a description" v-bind="props" />
Expand Down
29 changes: 29 additions & 0 deletions playgrounds/nuxt/app/pages/components/radio-group.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,19 @@ const itemsWithDescription = [
{ value: '2', label: 'Option 2', description: 'Description 2' },
{ value: '3', label: 'Option 3', description: 'Description 3' }
]
const itemsWithIcon = [
{ value: '1', label: 'System', icon: 'i-lucide-monitor' },
{ value: '2', label: 'Light', icon: 'i-lucide-sun' },
{ value: '3', label: 'Dark', icon: 'i-lucide-moon' }
]
const viewItems = [
{ value: 'table', label: 'Table', icon: 'i-lucide-table' },
{ value: 'board', label: 'Board', icon: 'i-lucide-kanban' },
{ value: 'calendar', label: 'Calendar', icon: 'i-lucide-calendar' },
{ value: 'list', label: 'List', icon: 'i-lucide-list' },
{ value: 'gallery', label: 'Gallery', icon: 'i-lucide-images' },
{ value: 'map', label: 'Map', icon: 'i-lucide-map' }
]
</script>

<template>
Expand All @@ -46,6 +59,7 @@ const itemsWithDescription = [
<URadioGroup :items="items" default-value="1" :orientation="orientation" v-bind="props" />
<URadioGroup :items="itemsLiteral" default-value="Option 1" :orientation="orientation" v-bind="props" />
<URadioGroup :items="itemsWithDescription" :orientation="orientation" v-bind="props" />
<URadioGroup :items="itemsWithIcon" :orientation="orientation" v-bind="props" />
<URadioGroup :items="items" disabled :orientation="orientation" v-bind="props" />
<URadioGroup :items="items" legend="Legend" :orientation="orientation" v-bind="props" />
<URadioGroup :items="items" legend="Legend" required :orientation="orientation" v-bind="props" />
Expand All @@ -62,4 +76,19 @@ const itemsWithDescription = [
</template>
</URadioGroup>
</Matrix>

<!-- Icon-on-top card grid built on the per-item `icon`, using only `ui` overrides -->
<div class="p-4 border-t border-default">
<URadioGroup
default-value="table"
variant="card"
indicator="hidden"
:items="viewItems"
:ui="{
fieldset: 'grid grid-cols-3 gap-2 w-96',
label: 'flex flex-col items-center gap-1.5',
leadingIcon: 'size-6 me-0'
}"
/>
</div>
</template>
6 changes: 6 additions & 0 deletions src/runtime/components/Checkbox.vue
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ export interface CheckboxProps<T = boolean> extends Pick<CheckboxRootProps<T>, '
* @IconifyIcon
*/
indeterminateIcon?: IconProps['name']
/**
* The icon displayed next to the label.
* @IconifyIcon
*/
leadingIcon?: IconProps['name']
class?: any
ui?: Checkbox['slots']
}
Expand Down Expand Up @@ -139,6 +144,7 @@ function onUpdate(value: any) {

<div v-if="(props.label || !!slots.label) || (props.description || !!slots.description)" data-slot="wrapper" :class="ui.wrapper({ class: props.ui?.wrapper })">
<component :is="(!props.variant || props.variant === 'list') ? Label : 'p'" v-if="props.label || !!slots.label" :for="id" data-slot="label" :class="ui.label({ class: props.ui?.label })">
<UIcon v-if="props.leadingIcon" :name="props.leadingIcon" data-slot="leadingIcon" :class="ui.leadingIcon({ class: props.ui?.leadingIcon })" />
<slot name="label" :label="props.label">
{{ props.label }}
</slot>
Expand Down
9 changes: 8 additions & 1 deletion src/runtime/components/CheckboxGroup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ export type CheckboxGroupItem = CheckboxGroupValue | {
description?: string
disabled?: boolean
value?: string
/**
* The icon displayed next to the label.
* @IconifyIcon
*/
icon?: IconProps['name']
class?: any
ui?: Pick<CheckboxGroup['slots'], 'item'> & Omit<Required<CheckboxProps>['ui'], 'root'>
[key: string]: any
Expand Down Expand Up @@ -89,6 +94,7 @@ import { useFormField } from '../composables/useFormField'
import { get, omit } from '../utils'
import { tv } from '../utils/tv'
import UCheckbox from './Checkbox.vue'
import type { IconProps } from './Icon.vue'

const _props = withDefaults(defineProps<CheckboxGroupProps<T, VK>>(), {
labelKey: 'label',
Expand Down Expand Up @@ -187,7 +193,8 @@ function onUpdate(value: any) {
<UCheckbox
v-for="item in normalizedItems"
:key="item.value"
v-bind="{ ...item, ...checkboxProps }"
v-bind="({ ...omit(item, ['icon']), ...checkboxProps } as any)"
:leading-icon="item.icon"
:color="color"
:highlight="highlight"
:size="size"
Expand Down
10 changes: 9 additions & 1 deletion src/runtime/components/RadioGroup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,13 @@ export type RadioGroupItem = RadioGroupValue | {
description?: string
disabled?: boolean
value?: RadioGroupValue
/**
* The icon displayed next to the label.
* @IconifyIcon
*/
icon?: IconProps['name']
class?: any
ui?: Pick<RadioGroup['slots'], 'item' | 'container' | 'base' | 'indicator' | 'wrapper' | 'label' | 'description'>
ui?: Pick<RadioGroup['slots'], 'item' | 'container' | 'base' | 'indicator' | 'wrapper' | 'label' | 'leadingIcon' | 'description'>
[key: string]: any
}

Expand Down Expand Up @@ -100,6 +105,8 @@ import { useForwardProps } from '../composables/useForwardProps'
import { useFormField } from '../composables/useFormField'
import { get } from '../utils'
import { tv } from '../utils/tv'
import type { IconProps } from './Icon.vue'
import UIcon from './Icon.vue'

const _props = withDefaults(defineProps<RadioGroupProps<T, VK>>(), {
valueKey: 'value' as never,
Expand Down Expand Up @@ -213,6 +220,7 @@ function onUpdate(value: any) {

<div v-if="(item.label || !!slots.label) || (item.description || !!slots.description)" data-slot="wrapper" :class="ui.wrapper({ class: [props.ui?.wrapper, item.ui?.wrapper] })">
<component :is="(!props.variant || props.variant === 'list') ? Label : 'p'" v-if="item.label || !!slots.label" :for="item.id" data-slot="label" :class="ui.label({ class: [props.ui?.label, item.ui?.label], disabled: item.disabled || disabled })">
<UIcon v-if="item.icon" :name="item.icon" data-slot="leadingIcon" :class="ui.leadingIcon({ class: [props.ui?.leadingIcon, item.ui?.leadingIcon] })" />
<slot name="label" :item="item" :model-value="(props.modelValue as RadioGroupValue)">
{{ item.label }}
</slot>
Expand Down
16 changes: 11 additions & 5 deletions src/theme/checkbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export default (options: Required<ModuleOptions>) => ({
icon: 'shrink-0 size-full',
wrapper: 'w-full',
label: 'block font-medium text-default',
leadingIcon: 'inline-block align-middle shrink-0 me-1.5',
description: 'text-muted'
},
variants: {
Expand Down Expand Up @@ -48,27 +49,32 @@ export default (options: Required<ModuleOptions>) => ({
xs: {
base: 'size-3',
container: 'h-4',
wrapper: 'text-xs'
wrapper: 'text-xs',
leadingIcon: 'size-3'
},
sm: {
base: 'size-3.5',
container: 'h-4',
wrapper: 'text-xs'
wrapper: 'text-xs',
leadingIcon: 'size-3.5'
},
md: {
base: 'size-4',
container: 'h-5',
wrapper: 'text-sm'
wrapper: 'text-sm',
leadingIcon: 'size-4'
},
lg: {
base: 'size-4.5',
container: 'h-5',
wrapper: 'text-sm'
wrapper: 'text-sm',
leadingIcon: 'size-4.5'
},
xl: {
base: 'size-5',
container: 'h-6',
wrapper: 'text-base'
wrapper: 'text-base',
leadingIcon: 'size-5'
}
},
required: {
Expand Down
Loading
Loading