Appearance
Multiselect
The FTMultiselect component is a searchable checkbox multiselect for choosing a subset of named items — as a dropdown (default) or an always-open inline panel. Items can carry an optional color swatch and an optional count. Two ordering modes: alphabetical (az) and drag-to-reorder (manual).
Basic usage
vue
<script setup lang="ts">
import { ref } from 'vue';
import { FTMultiselect, type IFTMultiselectItem } from '@fasttrack-solutions/vue-components-lib';
const items: IFTMultiselectItem[] = [
{ name: 'Casino', count: 128, color: '#e53e3e' },
{ name: 'Sports', count: 42, color: '#3182ce' },
{ name: 'Archived' }, // no swatch, no count
];
const selected = ref<string[]>([]);
</script>
<template>
<FTMultiselect v-model="selected" :items="items" label="Segments" placeholder="Segments" />
</template><script setup lang="ts">
import { ref } from 'vue';
import { FTMultiselect, type IFTMultiselectItem } from '@fasttrack-solutions/vue-components-lib';
const items: IFTMultiselectItem[] = [
{ name: 'Casino', count: 128, color: '#e53e3e' },
{ name: 'Sports', count: 42, color: '#3182ce' },
{ name: 'Archived' }, // no swatch, no count
];
const selected = ref<string[]>([]);
</script>
<template>
<FTMultiselect v-model="selected" :items="items" label="Segments" placeholder="Segments" />
</template>Playground
Properties
Selected: (none)
Mode: az
Mode: az
<script setup lang="ts">
import { ref } from 'vue';
const selected = ref([]);
const mode = ref("az");
const manualOrder = ref([]);
const items = ref([
{
"name": "Casino",
"count": 128,
"color": "#e53e3e"
},
{
"name": "Sports",
"count": 42,
"color": "#3182ce"
},
{
"name": "Poker",
"count": 7,
"color": "#38a169"
},
{
"name": "Archived"
},
{
"name": "Bingo",
"count": 0
}
]);
</script>
<template>
<FTMultiselect
v-model="selected"
v-model:mode="mode"
v-model:manualOrder="manualOrder"
:items="items"
label="Segments"
placeholder="Segments"
/>
</template>
Items
IFTMultiselectItem — name is both the display text and the identity key (v-model and manualOrder are arrays of names). count renders after the name only when present (0 is valid and renders).
The leading swatch column appears as soon as any item carries a color; items in that list without one render a muted placeholder so every row stays aligned. A list where no item has a color renders no swatch column at all.
Icons
iconPrefix sets the FontAwesome prefix for the caret, search glyph and drag grip (angle-down, magnifying-glass, grip-dots-vertical). It defaults to 'fas'; apps that register only sharp-solid icons must pass iconPrefix="fass" or the three icons render as nothing — which also disables manual reordering, since the drag handle is the grip icon.
Ordering modes
v-model:mode switches between 'az' (locale-aware alphabetical, default) and 'manual' (drag rows by the grip handle). Switching to manual seeds v-model:manualOrder with the current visible order if it is empty. Items missing from manualOrder are appended after the ordered ones, and an empty manualOrder renders alphabetically — so mounting straight into 'manual' gives the same order as switching into it, without the component writing to your state on mount.
Set showSort to false to hide the A-Z / Manual toggle for consumers that don't offer reordering. This hides the control only — v-model:mode still works, so you can pin the panel to either order, and the manual grips still appear if the mode is 'manual'. With the toggle hidden the bulk actions stay right-aligned, and if there are also no items the head bar is dropped rather than rendered empty.
Search and bulk actions
Searching filters rows by case-insensitive substring (searchable, on by default). Select All / Select None operate on the visible rows only — selections on filtered-out items are preserved. The search query clears when the dropdown closes.
Inline
Set inline to drop the trigger button and render the panel open, in-flow — for sidebars and filter rails.
Peer dependencies
FTMultiselect requires the consumer to install @vueuse/core, vue-draggable-next, and sortablejs (peer dependencies of this library — vue-draggable-next itself depends on sortablejs).
Props
| Prop | Type | Default | Description |
|---|---|---|---|
items | IFTMultiselectItem[] | — (required) | Items to choose from |
label | string | 'Items' | Label above the trigger (dropdown mode only) |
placeholder | string | 'Items' | Text inside the trigger button |
inline | boolean | false | Render the panel open and in-flow, no trigger |
searchable | boolean | true | Show the search input |
searchPlaceholder | string | 'Search…' | Search input placeholder |
showBadge | boolean | true | Show the selected/total badge in the trigger |
showSort | boolean | true | Show the A-Z / Manual sort toggle |
isRequired | boolean | false | Mark the field required (dropdown mode only) |
iconPrefix | string | 'fas' | FontAwesome prefix for caret/search/grip icons |
Naming: show* props hide a control without disabling what it controls — showSort: false hides the sort toggle, but v-model:mode still applies. Adjective props (searchable, inline) switch the capability or mode itself.
Required
isRequired renders the same * marker FTInput uses — same class name, colour token (--ft-input-required-color, falling back to --color-brand-pink-400), size and offset — so the two line up in a shared form. It also sets aria-required on the trigger. The marker lives inside the <label>, which only renders in dropdown mode, so it has no effect when inline is set.
Models
| Model | Type | Default | Description |
|---|---|---|---|
v-model | string[] | [] | Selected item names |
v-model:mode | 'az' | 'manual' | 'az' | Ordering mode |
v-model:manualOrder | string[] | [] | Item names in manual order |