mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-19 14:31:47 +01:00
docs(ComponentExample): automatically read code (#789)
This commit is contained in:
@@ -10,21 +10,7 @@ links:
|
||||
|
||||
Use a `v-model` to make the Input reactive.
|
||||
|
||||
::component-example
|
||||
#default
|
||||
:input-example
|
||||
|
||||
#code
|
||||
```vue
|
||||
<script setup>
|
||||
const value = ref('')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UInput v-model="value" />
|
||||
</template>
|
||||
```
|
||||
::
|
||||
:component-example{component="input-example"}
|
||||
|
||||
### Style
|
||||
|
||||
@@ -119,8 +105,8 @@ options:
|
||||
- name: color
|
||||
restriction: included
|
||||
values:
|
||||
- white
|
||||
- gray
|
||||
- white
|
||||
- gray
|
||||
excludedProps:
|
||||
- icon
|
||||
---
|
||||
@@ -197,32 +183,7 @@ baseProps:
|
||||
|
||||
You can for example create a clearable Input by injecting a [Button](/elements/button) in the `trailing` slot that displays when some text is entered.
|
||||
|
||||
::component-example
|
||||
#default
|
||||
:input-example-clearable
|
||||
|
||||
#code
|
||||
```vue
|
||||
<template>
|
||||
<UInput v-model="q" name="q" placeholder="Search..." icon="i-heroicons-magnifying-glass-20-solid" :ui="{ icon: { trailing: { pointer: '' } } }">
|
||||
<template #trailing>
|
||||
<UButton
|
||||
v-show="q !== ''"
|
||||
color="gray"
|
||||
variant="link"
|
||||
icon="i-heroicons-x-mark-20-solid"
|
||||
:padded="false"
|
||||
@click="q = ''"
|
||||
/>
|
||||
</template>
|
||||
</UInput>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const q = ref('')
|
||||
</script>
|
||||
```
|
||||
::
|
||||
:component-example{component="input-example-clearable"}
|
||||
|
||||
::callout{icon="i-heroicons-exclamation-triangle-20-solid"}
|
||||
As leading and trailing icons are wrapped around a `pointer-events-none` class, if you inject a clickable element in the slot, you need to remove this class to make it clickable by adding `:ui="{ icon: { trailing: { pointer: '' } } }"` to the Input.
|
||||
|
||||
@@ -17,54 +17,7 @@ The Form component requires the `validate` and `state` props for form validation
|
||||
- `message` - the error message to display.
|
||||
- `path` - the path to the form element matching the `name`.
|
||||
|
||||
::component-example
|
||||
#default
|
||||
:form-example-basic{class="space-y-4 w-60"}
|
||||
|
||||
#code
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import type { FormError, FormSubmitEvent } from '@nuxt/ui/dist/runtime/types'
|
||||
|
||||
const state = reactive({
|
||||
email: undefined,
|
||||
password: undefined
|
||||
})
|
||||
|
||||
const validate = (state: any): FormError[] => {
|
||||
const errors = []
|
||||
if (!state.email) errors.push({ path: 'email', message: 'Required' })
|
||||
if (!state.password) errors.push({ path: 'password', message: 'Required' })
|
||||
return errors
|
||||
}
|
||||
|
||||
async function submit (event: FormSubmitEvent<any>) {
|
||||
// Do something with data
|
||||
console.log(event.data)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UForm
|
||||
:validate="validate"
|
||||
:state="state"
|
||||
@submit="submit"
|
||||
>
|
||||
<UFormGroup label="Email" name="email">
|
||||
<UInput v-model="state.email" />
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup label="Password" name="password">
|
||||
<UInput v-model="state.password" type="password" />
|
||||
</UFormGroup>
|
||||
|
||||
<UButton type="submit">
|
||||
Submit
|
||||
</UButton>
|
||||
</UForm>
|
||||
</template>
|
||||
```
|
||||
::
|
||||
:component-example{component="form-example-basic" :componentProps='{"class": "space-y-4 w-60"}'}
|
||||
|
||||
## Schema
|
||||
|
||||
@@ -72,213 +25,20 @@ You can provide a schema from [Yup](#yup), [Zod](#zod) or [Joi](#joi), [Valibot]
|
||||
|
||||
### Yup
|
||||
|
||||
::component-example
|
||||
#default
|
||||
:form-example-yup{class="space-y-4 w-60"}
|
||||
|
||||
#code
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { object, string, InferType } from 'yup'
|
||||
import type { FormSubmitEvent } from '@nuxt/ui/dist/runtime/types'
|
||||
|
||||
const schema = object({
|
||||
email: string().email('Invalid email').required('Required'),
|
||||
password: string()
|
||||
.min(8, 'Must be at least 8 characters')
|
||||
.required('Required')
|
||||
})
|
||||
|
||||
type Schema = InferType<typeof schema>
|
||||
|
||||
const state = reactive({
|
||||
email: undefined,
|
||||
password: undefined
|
||||
})
|
||||
|
||||
async function submit (event: FormSubmitEvent<Schema>) {
|
||||
// Do something with event.data
|
||||
console.log(event.data)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UForm
|
||||
:schema="schema"
|
||||
:state="state"
|
||||
@submit="submit"
|
||||
>
|
||||
<UFormGroup label="Email" name="email">
|
||||
<UInput v-model="state.email" />
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup label="Password" name="password">
|
||||
<UInput v-model="state.password" type="password" />
|
||||
</UFormGroup>
|
||||
|
||||
<UButton type="submit">
|
||||
Submit
|
||||
</UButton>
|
||||
</UForm>
|
||||
</template>
|
||||
```
|
||||
::
|
||||
:component-example{component="form-example-yup" :componentProps='{"class": "space-y-4 w-60"}'}
|
||||
|
||||
### Zod
|
||||
|
||||
::component-example
|
||||
#default
|
||||
:form-example-zod{class="space-y-4 w-60"}
|
||||
|
||||
#code
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { z } from 'zod'
|
||||
import type { FormSubmitEvent } from '@nuxt/ui/dist/runtime/types'
|
||||
|
||||
const schema = z.object({
|
||||
email: z.string().email('Invalid email'),
|
||||
password: z.string().min(8, 'Must be at least 8 characters')
|
||||
})
|
||||
|
||||
type Schema = z.output<typeof schema>
|
||||
|
||||
const state = reactive({
|
||||
email: undefined,
|
||||
password: undefined
|
||||
})
|
||||
|
||||
async function submit (event: FormSubmitEvent<Schema>) {
|
||||
// Do something with data
|
||||
console.log(event.data)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UForm
|
||||
:schema="schema"
|
||||
:state="state"
|
||||
@submit="submit"
|
||||
>
|
||||
<UFormGroup label="Email" name="email">
|
||||
<UInput v-model="state.email" />
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup label="Password" name="password">
|
||||
<UInput v-model="state.password" type="password" />
|
||||
</UFormGroup>
|
||||
|
||||
<UButton type="submit">
|
||||
Submit
|
||||
</UButton>
|
||||
</UForm>
|
||||
</template>
|
||||
```
|
||||
::
|
||||
:component-example{component="form-example-zod" :componentProps='{"class": "space-y-4 w-60"}'}
|
||||
|
||||
### Joi
|
||||
|
||||
::component-example
|
||||
#default
|
||||
:form-example-joi{class="space-y-4 w-60"}
|
||||
:component-example{component="form-example-joi" :componentProps='{"class": "space-y-4 w-60"}'}
|
||||
|
||||
#code
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import Joi from 'joi'
|
||||
import type { FormSubmitEvent } from '@nuxt/ui/dist/runtime/types'
|
||||
|
||||
const schema = Joi.object({
|
||||
email: Joi.string().required(),
|
||||
password: Joi.string()
|
||||
.min(8)
|
||||
.required()
|
||||
})
|
||||
|
||||
const state = reactive({
|
||||
email: undefined,
|
||||
password: undefined
|
||||
})
|
||||
|
||||
async function submit (event: FormSubmitEvent<any>) {
|
||||
// Do something with event.data
|
||||
console.log(event.data)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UForm
|
||||
:schema="schema"
|
||||
:state="state"
|
||||
@submit="submit"
|
||||
>
|
||||
<UFormGroup label="Email" name="email">
|
||||
<UInput v-model="state.email" />
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup label="Password" name="password">
|
||||
<UInput v-model="state.password" type="password" />
|
||||
</UFormGroup>
|
||||
|
||||
<UButton type="submit">
|
||||
Submit
|
||||
</UButton>
|
||||
</UForm>
|
||||
</template>
|
||||
```
|
||||
::
|
||||
|
||||
### Valibot
|
||||
|
||||
::component-example
|
||||
#default
|
||||
:form-example-valibot{class="space-y-4 w-60"}
|
||||
|
||||
#code
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { string, object, email, minLength, Input } from 'valibot'
|
||||
import type { FormSubmitEvent } from '@nuxt/ui/dist/runtime/types'
|
||||
|
||||
const schema = object({
|
||||
email: string([email('Invalid email')]),
|
||||
password: string([minLength(8, 'Must be at least 8 characters')])
|
||||
})
|
||||
|
||||
type Schema = Input<typeof schema>
|
||||
|
||||
const state = reactive({
|
||||
email: undefined,
|
||||
password: undefined
|
||||
})
|
||||
|
||||
async function submit (event: FormSubmitEvent<Schema>) {
|
||||
// Do something with event.data
|
||||
console.log(event.data)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UForm
|
||||
:schema="schema"
|
||||
:state="state"
|
||||
@submit="submit"
|
||||
>
|
||||
<UFormGroup label="Email" name="email">
|
||||
<UInput v-model="state.email" />
|
||||
</UFormGroup>
|
||||
|
||||
<UFormGroup label="Password" name="password">
|
||||
<UInput v-model="state.password" type="password" />
|
||||
</UFormGroup>
|
||||
|
||||
<UButton type="submit">
|
||||
Submit
|
||||
</UButton>
|
||||
</UForm>
|
||||
</template>
|
||||
```
|
||||
::
|
||||
:component-example{component="form-example-valibot" :componentProps='{"class": "space-y-4 w-60"}'}
|
||||
|
||||
## Other libraries
|
||||
|
||||
@@ -372,10 +132,7 @@ async function submit (event: FormSubmitEvent<any>) {
|
||||
|
||||
The Form component automatically triggers validation upon `submit`, `input`, `blur` or `change` events. This ensures that any errors are displayed as soon as the user interacts with the form elements. You can control when validation happens this using the `validate-on` prop.
|
||||
|
||||
::component-example
|
||||
#default
|
||||
:form-example-elements{class="space-y-4 w-60"}
|
||||
::
|
||||
:component-example{component="form-example-elements" :componentProps='{"class": "space-y-4 w-60"}' hiddenCode }
|
||||
|
||||
::callout{icon="i-simple-icons-github" to="https://github.com/nuxt/ui/blob/dev/docs/components/content/examples/FormExampleElements.vue"}
|
||||
Take a look at the component!
|
||||
|
||||
@@ -10,21 +10,7 @@ links:
|
||||
|
||||
Use a `v-model` to make the Textarea reactive.
|
||||
|
||||
::component-example
|
||||
#default
|
||||
:textarea-example
|
||||
|
||||
#code
|
||||
```vue
|
||||
<script setup>
|
||||
const value = ref('')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UTextarea v-model="value" />
|
||||
</template>
|
||||
```
|
||||
::
|
||||
:component-example{component="textarea-example"}
|
||||
|
||||
### Style
|
||||
|
||||
|
||||
@@ -12,55 +12,13 @@ The Select component is a wrapper around the native `<select>` HTML element. For
|
||||
|
||||
Use a `v-model` to make the Select reactive alongside the `options` prop to pass an array of strings or objects.
|
||||
|
||||
::component-example
|
||||
#default
|
||||
:select-example
|
||||
|
||||
#code
|
||||
```vue
|
||||
<script setup>
|
||||
const countries = ['United States', 'Canada', 'Mexico']
|
||||
|
||||
const country = ref(countries[0])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<USelect v-model="country" :options="countries" />
|
||||
</template>
|
||||
```
|
||||
::
|
||||
:component-example{component="select-example"}
|
||||
|
||||
When using objects, you can configure which field will be used for display through the `option-attribute` prop that defaults to `label` and which field will be used for comparison through the `value-attribute` prop that defaults to `value`.
|
||||
|
||||
Adding a `disabled` key to the objects will control the disabled state of the option.
|
||||
|
||||
::component-example
|
||||
#default
|
||||
:select-example-objects
|
||||
|
||||
#code
|
||||
```vue
|
||||
<script setup>
|
||||
const countries = [{
|
||||
name: 'United States',
|
||||
value: 'US'
|
||||
}, {
|
||||
name: 'Canada',
|
||||
value: 'CA',
|
||||
disabled: true
|
||||
}, {
|
||||
name: 'Mexico',
|
||||
value: 'MX'
|
||||
}]
|
||||
|
||||
const country = ref('CA')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<USelect v-model="country" :options="countries" option-attribute="name" />
|
||||
</template>
|
||||
```
|
||||
::
|
||||
:component-example{component="select-example-objects"}
|
||||
|
||||
### Style
|
||||
|
||||
@@ -176,7 +134,7 @@ options:
|
||||
restriction: included
|
||||
values:
|
||||
- white
|
||||
- gray
|
||||
- gray
|
||||
excludedProps:
|
||||
- icon
|
||||
---
|
||||
|
||||
@@ -16,142 +16,23 @@ The `SelectMenu` component renders by default a [Select](/forms/select) componen
|
||||
|
||||
Like the `Select` component, you can use the `options` prop to pass an array of strings or objects.
|
||||
|
||||
::component-example
|
||||
#default
|
||||
:select-menu-example-basic{class="w-full lg:w-40"}
|
||||
|
||||
#code
|
||||
```vue
|
||||
<script setup>
|
||||
const people = ['Wade Cooper', 'Arlene Mccoy', 'Devon Webb', 'Tom Cook', 'Tanya Fox', 'Hellen Schmidt', 'Caroline Schultz', 'Mason Heaney', 'Claudie Smitham', 'Emil Schaefer']
|
||||
|
||||
const selected = ref(people[0])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<USelectMenu v-model="selected" :options="people" />
|
||||
</template>
|
||||
```
|
||||
::
|
||||
:component-example{component="select-menu-example-basic" :componentProps='{"class": "w-full lg:w-40"}'}
|
||||
|
||||
### Multiple
|
||||
|
||||
You can use the `multiple` prop to select multiple values.
|
||||
|
||||
::component-example
|
||||
#default
|
||||
:select-menu-example-multiple{class="w-full lg:w-40"}
|
||||
|
||||
#code
|
||||
```vue
|
||||
<script setup>
|
||||
const people = [...]
|
||||
|
||||
const selected = ref([])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<USelectMenu v-model="selected" :options="people" multiple placeholder="Select people" />
|
||||
</template>
|
||||
```
|
||||
::
|
||||
:component-example{component="select-menu-example-multiple" :componentProps='{"class": "w-full lg:w-40"}'}
|
||||
|
||||
### Objects
|
||||
|
||||
You can pass an array of objects to `options` and either compare on the whole object or use the `by` prop to compare on a specific key. You can configure which field will be used to display the label through the `option-attribute` prop that defaults to `label`.
|
||||
|
||||
::component-example
|
||||
#default
|
||||
:select-menu-example-objects{class="w-full lg:w-40"}
|
||||
#code
|
||||
```vue
|
||||
<script setup>
|
||||
const people = [{
|
||||
id: 'benjamincanac',
|
||||
label: 'benjamincanac',
|
||||
href: 'https://github.com/benjamincanac',
|
||||
target: '_blank',
|
||||
avatar: { src: 'https://avatars.githubusercontent.com/u/739984?v=4' }
|
||||
},
|
||||
{
|
||||
id: 'Atinux',
|
||||
label: 'Atinux',
|
||||
href: 'https://github.com/Atinux',
|
||||
target: '_blank',
|
||||
avatar: { src: 'https://avatars.githubusercontent.com/u/904724?v=4' }
|
||||
},
|
||||
{
|
||||
id: 'smarroufin',
|
||||
label: 'smarroufin',
|
||||
href: 'https://github.com/smarroufin',
|
||||
target: '_blank',
|
||||
avatar: { src: 'https://avatars.githubusercontent.com/u/7547335?v=4' }
|
||||
},
|
||||
{
|
||||
id: 'nobody',
|
||||
label: 'Nobody',
|
||||
icon: 'i-heroicons-user-circle'
|
||||
}]
|
||||
|
||||
const selected = ref(people[0])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<USelectMenu v-model="selected" :options="people">
|
||||
<template #label>
|
||||
<UIcon v-if="selected.icon" :name="selected.icon" class="w-4 h-4" />
|
||||
<UAvatar v-else-if="selected.avatar" v-bind="selected.avatar" size="3xs" />
|
||||
|
||||
{{ selected.label }}
|
||||
</template>
|
||||
</USelectMenu>
|
||||
</template>
|
||||
```
|
||||
::
|
||||
:component-example{component="select-menu-example-objects" :componentProps='{"class": "w-full lg:w-40"}'}
|
||||
|
||||
If you only want to select a single object property rather than the whole object as value, you can set the `value-attribute` property. This prop defaults to `null`.
|
||||
|
||||
::component-example
|
||||
#default
|
||||
:select-menu-example-objects-value-attribute{class="w-full lg:w-40"}
|
||||
|
||||
#code
|
||||
```vue
|
||||
<script setup>
|
||||
const people = [{
|
||||
id: 1,
|
||||
name: 'Wade Cooper'
|
||||
}, {
|
||||
id: 2,
|
||||
name: 'Arlene Mccoy'
|
||||
}, {
|
||||
id: 3,
|
||||
name: 'Devon Webb'
|
||||
}, {
|
||||
id: 4,
|
||||
name: 'Tom Cook'
|
||||
}]
|
||||
|
||||
const selected = ref(people[0].id)
|
||||
|
||||
const current = computed(() => people.find(person => person.id === selected.value))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<USelectMenu
|
||||
v-model="selected"
|
||||
:options="people"
|
||||
placeholder="Select people"
|
||||
value-attribute="id"
|
||||
option-attribute="name"
|
||||
>
|
||||
<template #label>
|
||||
{{ current.name }}
|
||||
</template>
|
||||
</USelectMenu>
|
||||
</template>
|
||||
```
|
||||
::
|
||||
:component-example{component="select-menu-example-objects-value-attribute" :componentProps='{"class": "w-full lg:w-40"}'}
|
||||
|
||||
### Icon
|
||||
|
||||
@@ -200,33 +81,7 @@ Pass a function to the `searchable` prop to customize the search behavior and fi
|
||||
|
||||
Use the `debounce` prop to adjust the delay of the function.
|
||||
|
||||
::component-example
|
||||
#default
|
||||
:select-menu-example-async-search{class="w-full lg:w-40"}
|
||||
|
||||
#code
|
||||
```vue
|
||||
<script setup>
|
||||
const search = async (q) => {
|
||||
const users = await $fetch('https://jsonplaceholder.typicode.com/users', { params: { q } })
|
||||
|
||||
return users.map(user => ({ id: user.id, label: user.name, suffix: user.email })).filter(Boolean)
|
||||
}
|
||||
|
||||
const selected = ref([])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<USelectMenu
|
||||
v-model="selected"
|
||||
:searchable="search"
|
||||
placeholder="Search for a user..."
|
||||
multiple
|
||||
by="id"
|
||||
/>
|
||||
</template>
|
||||
```
|
||||
::
|
||||
:component-example{component="select-menu-example-async-search" :componentProps='{"class": "w-full lg:w-40"}'}
|
||||
|
||||
### Create option
|
||||
|
||||
@@ -234,99 +89,7 @@ Use the `creatable` prop to enable the creation of new options when the search d
|
||||
|
||||
Try to search for something that doesn't exist in the example below.
|
||||
|
||||
::component-example
|
||||
#default
|
||||
:select-menu-example-creatable{class="w-full lg:w-40"}
|
||||
|
||||
#code
|
||||
```vue
|
||||
<script setup>
|
||||
const options = ref([
|
||||
{ id: 1, name: 'bug', color: 'd73a4a' },
|
||||
{ id: 2, name: 'documentation', color: '0075ca' },
|
||||
{ id: 3, name: 'duplicate', color: 'cfd3d7' },
|
||||
{ id: 4, name: 'enhancement', color: 'a2eeef' },
|
||||
{ id: 5, name: 'good first issue', color: '7057ff' },
|
||||
{ id: 6, name: 'help wanted', color: '008672' },
|
||||
{ id: 7, name: 'invalid', color: 'e4e669' },
|
||||
{ id: 8, name: 'question', color: 'd876e3' },
|
||||
{ id: 9, name: 'wontfix', color: 'ffffff' }
|
||||
])
|
||||
|
||||
const selected = ref([])
|
||||
|
||||
const labels = computed({
|
||||
get: () => selected.value,
|
||||
set: async (labels) => {
|
||||
const promises = labels.map(async (label) => {
|
||||
if (label.id) {
|
||||
return label
|
||||
}
|
||||
|
||||
// In a real app, you would make an API call to create the label
|
||||
const response = {
|
||||
name: label.name,
|
||||
color: generateColorFromString(label.name)
|
||||
}
|
||||
|
||||
options.value.push(response)
|
||||
|
||||
return response
|
||||
})
|
||||
|
||||
selected.value = await Promise.all(promises)
|
||||
}
|
||||
})
|
||||
|
||||
// Look at the component example to see how this is used
|
||||
function generateColorFromString (str) {
|
||||
// ...
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<USelectMenu
|
||||
v-model="labels"
|
||||
by="id"
|
||||
name="labels"
|
||||
:options="options"
|
||||
option-attribute="name"
|
||||
multiple
|
||||
searchable
|
||||
creatable
|
||||
>
|
||||
<template #label>
|
||||
<template v-if="labels.length">
|
||||
<span class="flex items-center -space-x-1">
|
||||
<span v-for="label of labels" :key="label.id" class="flex-shrink-0 w-2 h-2 mt-px rounded-full" :style="{ background: `#${label.color}` }" />
|
||||
</span>
|
||||
<span>{{ labels.length }} label{{ labels.length > 1 ? 's' : '' }}</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span class="text-gray-500 dark:text-gray-400 truncate">Select labels</span>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<template #option="{ option }">
|
||||
<span
|
||||
class="flex-shrink-0 w-2 h-2 mt-px rounded-full"
|
||||
:style="{ background: `#${option.color}` }"
|
||||
/>
|
||||
<span class="truncate">{{ option.name }}</span>
|
||||
</template>
|
||||
|
||||
<template #option-create="{ option }">
|
||||
<span class="flex-shrink-0">New label:</span>
|
||||
<span
|
||||
class="flex-shrink-0 w-2 h-2 mt-px rounded-full -mx-1"
|
||||
:style="{ background: `#${generateColorFromString(option.name)}` }"
|
||||
/>
|
||||
<span class="block truncate">{{ option.name }}</span>
|
||||
</template>
|
||||
</USelectMenu>
|
||||
</template>
|
||||
```
|
||||
::
|
||||
:component-example{component="select-menu-example-creatable" :componentProps='{"class": "w-full lg:w-40"}'}
|
||||
|
||||
## Slots
|
||||
|
||||
@@ -334,125 +97,25 @@ function generateColorFromString (str) {
|
||||
|
||||
You can override the `#label` slot and handle the display yourself.
|
||||
|
||||
::component-example
|
||||
#default
|
||||
:select-menu-example-multiple-slot{class="w-full lg:w-40"}
|
||||
|
||||
#code
|
||||
```vue
|
||||
<script setup>
|
||||
const people = [...]
|
||||
|
||||
const selected = ref([])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<USelectMenu v-model="selected" :options="people" multiple>
|
||||
<template #label>
|
||||
<span v-if="selected.length" class="truncate">{{ selected.join(', ') }}</span>
|
||||
<span v-else>Select people</span>
|
||||
</template>
|
||||
</USelectMenu>
|
||||
</template>
|
||||
```
|
||||
::
|
||||
:component-example{component="select-menu-example-multiple-slot" :componentProps='{"class": "w-full lg:w-40"}'}
|
||||
|
||||
### `default`
|
||||
|
||||
You can also override the `#default` slot entirely.
|
||||
|
||||
::component-example
|
||||
#default
|
||||
:select-menu-example-button{class="w-full lg:w-40"}
|
||||
|
||||
#code
|
||||
```vue
|
||||
<script setup>
|
||||
const people = [...]
|
||||
|
||||
const selected = ref(people[3])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<USelectMenu v-slot="{ open }" v-model="selected" :options="people">
|
||||
<UButton color="gray" class="flex-1 justify-between">
|
||||
{{ selected }}
|
||||
|
||||
<UIcon name="i-heroicons-chevron-right-20-solid" class="w-5 h-5 transition-transform" :class="[open && 'transform rotate-90']" />
|
||||
</UButton>
|
||||
</USelectMenu>
|
||||
</template>
|
||||
```
|
||||
::
|
||||
:component-example{component="select-menu-example-button" :componentProps='{"class": "w-full lg:w-40"}'}
|
||||
|
||||
### `option`
|
||||
|
||||
Use the `#option` slot to customize the option content. You will have access to the `option`, `active` and `selected` properties in the slot scope.
|
||||
|
||||
::component-example
|
||||
#default
|
||||
:select-menu-example-option-slot{class="w-full lg:w-40"}
|
||||
|
||||
#code
|
||||
```vue
|
||||
<script setup>
|
||||
const people = [
|
||||
{ name: 'Wade Cooper', online: true },
|
||||
{ name: 'Arlene Mccoy', online: false },
|
||||
{ name: 'Devon Webb', online: false },
|
||||
{ name: 'Tom Cook', online: true },
|
||||
{ name: 'Tanya Fox', online: false },
|
||||
{ name: 'Hellen Schmidt', online: true },
|
||||
{ name: 'Caroline Schultz', online: true },
|
||||
{ name: 'Mason Heaney', online: false },
|
||||
{ name: 'Claudie Smitham', online: true },
|
||||
{ name: 'Emil Schaefer', online: false }
|
||||
]
|
||||
|
||||
const selected = ref(people[3])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<USelectMenu v-model="selected" :options="people" option-attribute="name">
|
||||
<template #label>
|
||||
<span :class="[selected.online ? 'bg-green-400' : 'bg-gray-200', 'inline-block h-2 w-2 flex-shrink-0 rounded-full']" aria-hidden="true" />
|
||||
<span class="truncate">{{ selected.name }}</span>
|
||||
</template>
|
||||
|
||||
<template #option="{ option: person }">
|
||||
<span :class="[person.online ? 'bg-green-400' : 'bg-gray-200', 'inline-block h-2 w-2 flex-shrink-0 rounded-full']" aria-hidden="true" />
|
||||
<span class="truncate">{{ person.name }}</span>
|
||||
</template>
|
||||
</USelectMenu>
|
||||
</template>
|
||||
```
|
||||
::
|
||||
:component-example{component="select-menu-example-option-slot" :componentProps='{"class": "w-full lg:w-40"}'}
|
||||
|
||||
### `option-empty`
|
||||
|
||||
Use the `#option-empty` slot to customize the content displayed when the `searchable` prop is `true` and there is no options. You will have access to the `query` property in the slot scope.
|
||||
|
||||
::component-example
|
||||
#default
|
||||
:select-menu-example-option-empty-slot{class="w-full lg:w-40"}
|
||||
|
||||
#code
|
||||
```vue
|
||||
<script setup>
|
||||
const people = ['Wade Cooper', 'Arlene Mccoy', 'Devon Webb', 'Tom Cook', 'Tanya Fox', 'Hellen Schmidt', 'Caroline Schultz', 'Mason Heaney', 'Claudie Smitham', 'Emil Schaefer']
|
||||
|
||||
const selected = ref(people[0])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<USelectMenu v-model="selected" :options="people" searchable>
|
||||
<template #option-empty="{ query }">
|
||||
<q>{{ query }}</q> not found
|
||||
</template>
|
||||
</USelectMenu>
|
||||
</template>
|
||||
```
|
||||
::
|
||||
:component-example{component="select-menu-example-option-empty-slot" :componentProps='{"class": "w-full lg:w-40"}'}
|
||||
|
||||
### `option-create`
|
||||
|
||||
|
||||
@@ -10,21 +10,7 @@ links:
|
||||
|
||||
Use a `v-model` to make the Checkbox reactive.
|
||||
|
||||
::component-example
|
||||
#default
|
||||
:checkbox-example
|
||||
|
||||
#code
|
||||
```vue
|
||||
<script setup>
|
||||
const selected = ref(true)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UCheckbox v-model="selected" name="notifications" label="Notifications" />
|
||||
</template>
|
||||
```
|
||||
::
|
||||
:component-example{component="checkbox-example"}
|
||||
|
||||
### Label
|
||||
|
||||
|
||||
@@ -10,35 +10,7 @@ links:
|
||||
|
||||
Use a `v-model` to make the Radio reactive.
|
||||
|
||||
::component-example
|
||||
#default
|
||||
:radio-example
|
||||
|
||||
#code
|
||||
```vue
|
||||
<script setup>
|
||||
const methods = [{
|
||||
name: 'email',
|
||||
value: 'email',
|
||||
label: 'Email'
|
||||
}, {
|
||||
name: 'sms',
|
||||
value: 'sms',
|
||||
label: 'Phone (SMS)'
|
||||
}, {
|
||||
name: 'push',
|
||||
value: 'push',
|
||||
label: 'Push notification'
|
||||
}]
|
||||
|
||||
const selected = ref('sms')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<URadio v-for="method of methods" :key="method.name" v-model="selected" v-bind="method" />
|
||||
</template>
|
||||
```
|
||||
::
|
||||
:component-example{component="radio-example"}
|
||||
|
||||
### Label
|
||||
|
||||
|
||||
@@ -13,21 +13,7 @@ links:
|
||||
|
||||
Use a `v-model` to make the Toggle reactive.
|
||||
|
||||
::component-example
|
||||
#default
|
||||
:toggle-example
|
||||
|
||||
#code
|
||||
```vue
|
||||
<script setup>
|
||||
const selected = ref(false)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UToggle v-model="selected" />
|
||||
</template>
|
||||
```
|
||||
::
|
||||
|
||||
### Style
|
||||
|
||||
|
||||
@@ -10,21 +10,7 @@ links:
|
||||
|
||||
Use a `v-model` to make the Range reactive.
|
||||
|
||||
::component-example
|
||||
#default
|
||||
:range-example
|
||||
|
||||
#code
|
||||
```vue
|
||||
<script setup>
|
||||
const value = ref(50)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<URange v-model="value" />
|
||||
</template>
|
||||
```
|
||||
::
|
||||
:component-example{component="range-example"}
|
||||
|
||||
### Style
|
||||
|
||||
|
||||
@@ -112,23 +112,7 @@ Use the `error` prop to display an error message below the form element.
|
||||
|
||||
When used together with the `help` prop, the `error` prop will take precedence.
|
||||
|
||||
::component-example
|
||||
#default
|
||||
:form-group-error-example
|
||||
|
||||
#code
|
||||
```vue
|
||||
<template>
|
||||
<UFormGroup v-slot="{ error }" label="Email" :error="!email && 'You must enter an email'" help="This is a nice email!">
|
||||
<UInput v-model="email" type="email" placeholder="Enter email" :trailing-icon="error && 'i-heroicons-exclamation-triangle-20-solid'" />
|
||||
</UFormGroup>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const email = ref('')
|
||||
</script>
|
||||
```
|
||||
::
|
||||
:component-example{component="form-group-error-example"}
|
||||
|
||||
::callout{icon="i-heroicons-light-bulb"}
|
||||
The `error` prop will automatically set the `color` prop of the form element to `red`.
|
||||
@@ -274,30 +258,7 @@ props:
|
||||
|
||||
Use the `#error` slot to set the custom content for error.
|
||||
|
||||
::component-example
|
||||
#default
|
||||
:form-group-error-slot-example{class="w-60"}
|
||||
|
||||
#code
|
||||
```vue
|
||||
<template>
|
||||
<UFormGroup label="Email" :error="!email && 'You must enter an email'" help="This is a nice email!">
|
||||
<template #default="{ error }">
|
||||
<UInput v-model="email" type="email" placeholder="Enter email" :trailing-icon="error ? 'i-heroicons-exclamation-triangle-20-solid' : undefined" />
|
||||
</template>
|
||||
|
||||
<template #error="{ error }">
|
||||
<UAlert v-if="error" icon="i-heroicons-exclamation-triangle-20-solid" :title="error" color="red" />
|
||||
<UAlert v-else icon="i-heroicons-check-circle-20-solid" title="Your email is valid" color="green" />
|
||||
</template>
|
||||
</UFormGroup>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const email = ref('')
|
||||
</script>
|
||||
```
|
||||
::
|
||||
:component-example{component="form-group-error-slot-example" :componentProps='{"class": "w-60"}'}
|
||||
|
||||
## Props
|
||||
|
||||
|
||||
Reference in New Issue
Block a user