Appearance
Appearance
import Pills from "@ui/Pills.vue"Show a dense list of pills representing tags, categories or options. Users can select a subset of given options and create new ones.
/**
* Use `get` to read the pills into your app.
* Use `set` to write your app's state back into the pills.
*/
const props = defineProps<{
icon?: string,
placeholder?: string,
label?: string,
cancel?: string,
get: (v: Model) => void,
set: (v: Model) => Model
}>()const model = ref<Model>({ currents: [] })The reactive functions get and set are named from the perspective of the app.
get to read the user-updated pills into your app.set to write your app's state back into the pills.The model you provide will be mutated by this component:
currents: these items are currently selectedothers: these items are currently not selected (but can be selected by the user). This prop is optional. By adding it, you allow users to change the selection.Each item has a label of type string as well as a type of either:
custom: the user can edit its label orpreset: the user cannot edit its labeltype Item = { type: 'custom' | 'preset', label: string }
type Model = {
currents: Item[],
others?: Item[],
}NOTE
To convey the intent of the pills editor, define a meaningful text label with the label prop. Read more on form field labelling
const nullModel = ref({
currents: []
}) satisfies Model;<Pills v-model="nullModel" />const staticModel = ref({
currents: [
{ label: "#noise", type: 'preset' },
{ label: "#fieldRecording", type: 'preset' },
{ label: "#experiment", type: 'preset' }
]
} satisfies Model);<Pills
:get="(v) => { return }"
:set="() => staticModel"
/>By adding custom options, you make the Pills instance interactive. Use reactive methods such as computed(...) and watch(...) to bind the model.
Note that this component will automatically add an empty pill to the end of the model because it made the implementation more straightforward. Use `filter(({ label }) => label !== '') to ignore it when reading the model.
const simpleCustomModel = ref({
currents: [],
others: []
})<Pills
:get="(v) => { simpleCustomModel = v }"
:set="() => staticModel"
/>const customModel = ref({
...staticModel,
others: [
{ label: "#MyTag1", type: 'custom' },
{ label: "#MyTag2", type: 'custom' }
]
} satisfies Model);<Pills
:get="(v) => { customModel = v }"
:set="() => customModel"
label="Custom Tags"
cancel="Cancel"
/>In the following example, others are shared among two Pills lists.
const sharedOthers = ref<Model['others']>(customModel.value.others)
const currentA = ref<Model['currents']>([{ label: 'A', type: 'preset' }])
const currentB = ref<Model['currents']>([])
const updateSharedOthers = (others: Item[]) => {
sharedOthers.value
= unionBy(sharedOthers.value, others, 'label')
.filter(item =>
[...currentA.value, ...currentB.value].every(({ label }) =>
item.label !== label
))
} Shared among A and B:
#myTag1, #myTag2
You can use the same pattern to influence the model from an outside source:
const tags = ref<string[]>(['1', '2'])
const sharedTags = ref<string[]>(['3'])
const setTags = (v: string[]) => {
sharedTags.value
= [...tags.value, ...sharedTags.value].filter(tag => !(v.includes(tag)))
tags.value
= v
}1, 2
3
Using this component
<Pills
:get="p => { pills = p }"
:set="_ => pills"
/>Guide: Creating accessible forms