```ts import Pills from "~/components/ui/Pills.vue" ``` # Pills Show a dense list of pills representing tags, categories or options. Users can select a subset of given options and create new ones. The model you provide will be mutated by this component: - `currents`: these items are currently selected - `others`: 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 or - `preset`: the user cannot edit its label ```ts type Item = { type: 'custom' | 'preset', label: string } type Model = { currents: Item[], others?: Item[], } ``` ## No pills ```ts const nullModel = ref({ currents: [] }) satisfies Model; ``` ```vue-html ``` ## Static list of pills ```ts const staticModel = ref({ currents: [ { label: "#noise", type: 'preset' }, { label: "#fieldRecording", type: 'preset' }, { label: "#experiment", type: 'preset' } ] } satisfies Model); ``` ```vue-html ``` ## Let users add, remove and edit custom pills By adding `custom` options, you make the `Pills` instance interactive. Use [reactive](https://vuejs.org/guide/essentials/reactivity-fundamentals.html#reactive-variables-with-ref) methods [such as `computed(...)`](https://vuejs.org/guide/essentials/computed.html) 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. ### Minimal example ```ts const simpleCustomModel = ref({ currents: [], others: [] }) ``` ```vue-html ``` ### Complex example ```ts const customModel = ref({ ...staticModel, others: [ { label: "#MyTag1", type: 'custom' }, { label: "#MyTag2", type: 'custom' } ] } satisfies Model); ``` ```vue-html ``` ## Bind data with an external sink In the following example, `others` are shared among two `Pills` lists. ```ts const sharedOthers = ref(customModel.value.others) const currentA = ref([{ label: 'A', type: 'preset' }]) const currentB = ref([]) const updateSharedOthers = (others: Item[]) => { sharedOthers.value = unionBy(sharedOthers.value, others, 'label') .filter(item => [...currentA.value, ...currentB.value].every(({ label }) => item.label !== label )) } ``` ## Bind data with an external source You can use the same pattern to influence the model from an outside source: ```ts const tags = ref(['1', '2']) const sharedTags = ref(['3']) const setTags = (v: string[]) => { sharedTags.value = [...tags.value, ...sharedTags.value].filter(tag => !(v.includes(tag))) tags.value = v } ```