Drawer Collection Component
The v-drawer-collection component is a specialized dialog in Directus that enables users to select items from a database collection. It provides a rich interface for browsing, searching, and filtering collection data before selecting one or more items.
Key Use Cases:
- Relationship field pickers (one-to-many, many-to-many)
- Item selection in modal dialogs
- Filtered collection browsing
- Single or multiple item selection modes
Component API
Props
| Prop | Type | Default | Description |
|---|---|---|---|
active | boolean | false | Controls whether the drawer is open. When undefined, internal state is used. |
selection | (number | string)[] | [] | Array of currently selected item IDs. |
collection | string | required | The database collection name to display. |
multiple | boolean | false | When true, allows selecting multiple items. When false, only one item can be selected. |
filter | Filter | null | Additional system filters to apply to the collection query. |
drawerProps | VDrawerProps | {} | Additional props to pass to the underlying VDrawer component. |
Emits
| Event | Payload | Description |
|---|---|---|
update:active | boolean | Fired when the drawer's open/closed state changes. |
input | (number | string)[] | null | Fired when the user confirms selection. Contains the selected item IDs. |
How It Works
Selection Management
The component maintains internal state for selections and tracks whether the user has made changes since opening. Key behaviors:
- Initial Load: When the drawer opens, the current selection is stored as the "initial selection"
- Change Tracking: A
hasSelectionChangedcomputed property tracks if the selection differs from when the drawer opened - Save: The
@applyevent (fromv-drawer) triggers a save, which emits theinputevent only if changes were made - Cancel: The
@cancelevent closes the drawer without emittinginput
Layout System
The component uses Directus's layout system to display collection items from the global or user's preset:
- Supports multiple layout types (tabular, card, etc.) via
layout-${type}components - Users can switch layouts using layout action buttons on the collection which will be adopted by the drawer as well.
- Layout-specific options and queries are managed locally and are not remembered outside the drawer.
- Filters are combined from both user preferences and system permissions
Search & Filtering
- Search: A search input allows real-time text filtering
- Filters: System filters and user-preset filters are merged
- Dynamic Updates: Layout options and queries update reactively as users interact
Usage Example
Basic Single-Item Selection
The Drawer Collection is available to extensions without needing to import in your script. Here is an example of a basic single item selection drawer:
<script setup lang="ts">
import { ref } from 'vue';
const isDrawerOpen = ref(false);
const selectedAuthorId = ref<string | number | null>(null);
const handleItemSelected = (selectedIds: (string | number)[] | null) => {
if (selectedIds && selectedIds.length > 0) {
selectedAuthorId.value = selectedIds[0];
console.log(`Selected author ID: ${selectedAuthorId.value}`);
}
};
</script>
<template>
<div>
<button @click="isDrawerOpen = true">
Select an Author
</button>
<v-drawer-collection
v-model:active="isDrawerOpen"
:selection="selectedAuthorId ? [selectedAuthorId] : []"
collection="authors"
@input="handleItemSelected"
/>
<div v-if="selectedAuthorId">
Selected Author ID: {{ selectedAuthorId }}
</div>
</div>
</template>
Multiple Selection with Filtering
If you want to accept multiple selection from the drawer collection, use the following example:
<script setup lang="ts">
import { ref } from 'vue';
import type { Filter } from '@directus/types';
const isDrawerOpen = ref(false);
const selectedUserIds = ref<(string | number)[]>([]);
// Only show active users (status = 'active')
const activeUsersFilter: Filter = {
status: { _eq: 'active' }
};
const handleUsersSelected = (selectedIds: (string | number)[] | null) => {
if (selectedIds) {
selectedUserIds.value = selectedIds;
console.log(`Selected ${selectedIds.length} users`);
}
};
</script>
<template>
<div>
<button @click="isDrawerOpen = true">
Select Users
</button>
<v-drawer-collection
v-model:active="isDrawerOpen"
:selection="selectedUserIds"
:multiple="true"
collection="directus_users"
:filter="activeUsersFilter"
@input="handleUsersSelected"
/>
<div v-if="selectedUserIds.length > 0">
<p>Selected {{ selectedUserIds.length }} users:</p>
<ul>
<li v-for="id in selectedUserIds" :key="id">
User ID: {{ id }}
</li>
</ul>
</div>
</div>
</template>
Advanced: Custom Drawer Styling
If you want to make some changes to the icon or title of the Drawer, you can use the drawer-props attribute. Here is an example:
<script setup lang="ts">
import { ref } from 'vue';
import DrawerCollection from '@/views/private/components/drawer-collection.vue';
const isDrawerOpen = ref(false);
const selectedItemId = ref<string | number | null>(null);
const customDrawerProps = {
icon: 'link',
title: 'Link Related Item',
};
const handleSelect = (selectedIds: (string | number)[] | null) => {
if (selectedIds && selectedIds[0]) {
selectedItemId.value = selectedIds[0];
}
};
</script>
<template>
<DrawerCollection
v-model:active="isDrawerOpen"
:selection="selectedItemId ? [selectedItemId] : []"
collection="projects"
:drawer-props="customDrawerProps"
@input="handleSelect"
/>
</template>
Internal Architecture
Composables Used
useCollection()- Retrieves collection metadata (name, icon, etc.)useLayout()- Manages layout rendering and stateusePreset()- Handles user layout preferences, search, and filters
Key Slots
The component forwards all slots from its parent, allowing custom content injection:
<v-drawer-collection collection="authors">
<template #title>Custom title content</template>
<template #subtitle>Custom subtitle content</template>
<template #title-outer:prepend>Custom content before the title container</template>
<template #actions:prepend>Custom content before the actions</template>
<template #actions>Custom content in the actions container</template>
<template #actions:append>Custom content after the actions</template>
<template #header:append>Custom content after the header</template>
<template #sidebar>Custom content for the sidebar</template>
</v-drawer-collection>
Important Behaviors
- Drawer State Sync: The
v-model:activebinding keeps the drawer state in sync with parent components - Selection Stability: Selection is only committed when the user clicks the tick button (apply action)
- Filter Merging: User filters are merged with their permissions, allowing flexible and secure query building
- No Results Handling: A helpful info message displays when no items match the filter criteria
- Dynamic Layouts: Users can switch between different layout types within the drawer
Performance Considerations
- Selections are stored locally and only emitted on confirmation
- Layout options are cached and updated only when necessary
- The component respects the collection's configured display settings