Drawer Files Component
The v-drawer-files component is a drawer from Directus that allows users to browse and select files from the directus_filescollection with folder navigation capabilities. This component is natively available to extensions and doesn't need to be imported.
Key Features:
- Browse files organized in folders
- Select single or multiple files
- Context-aware filtering based on current folder and special folders
- Support for access control integration with user permissions
Component API
Props
The following properties are available:
collection- The collection to browse files from. Defaults to Directus' built-indirectus_filescollection. You can specify a custom collection if needed.folder- Sets the root folder ID that constrains browsing. If set, Users can only navigate within this folder and its subfolders.field- A unique identifier (typically the field name) used to scope the component's session storage. This allows multiple instances of the component on the same page to maintain independent folder states. For example, usingfield="avatar"andfield="banner"on the same page keeps their navigation states separate. Normally this will be the field key of the current interface but layouts can use custom strings depending on the use case.filter- Additional Directus filters to apply to the file list. These are merged with the component's internal folder filtering logic. This can be useful if you need to limit what files can be seen, such and images or documents.
How It Works
Basic Usage
Here's how to use the v-drawer-files component in your extension:
<script setup lang="ts">
import { ref } from 'vue';
// Track whether the drawer is open
const showFileDrawer = ref(false);
// Handle selected files
const handleFileSelect = (files: any[]) => {
console.log('Selected files:', files);
// Process selected files here
};
</script>
<template>
<div>
<!-- Button to open the file drawer -->
<button @click="showFileDrawer = true">
Select Files
</button>
<!-- File drawer component -->
<v-drawer-files
v-model:active="showFileDrawer"
collection="directus_files"
@input="handleFileSelect"
/>
</div>
</template>
Advanced Usage Example
Here's a more advanced example with custom filtering and field scoping:
<script setup lang="ts">
import { ref } from 'vue';
import { Filter } from '@directus/types';
const showAvatarDrawer = ref(false);
const showBannerDrawer = ref(false);
const selectedAvatar = ref<any>(null);
const selectedBanner = ref<any>(null);
// Optional: Filter to only show image files
const imageFilter: Filter = {
type: {
_in: ['image/jpeg', 'image/png', 'image/webp'],
},
};
const handleAvatarSelect = (files: any[]) => {
if (files.length > 0) {
selectedAvatar.value = files[0]; // Single select
}
};
const handleBannerSelect = (files: any[]) => {
if (files.length > 0) {
selectedBanner.value = files[0];
}
};
</script>
<template>
<div>
<!-- Avatar file selector -->
<div>
<button @click="showAvatarDrawer = true">
Select Avatar
</button>
<v-drawer-files
v-model:active="showAvatarDrawer"
field="avatar"
folder="<avatars-folder-id>"
:filter="imageFilter"
@input="handleAvatarSelect"
/>
<div v-if="selectedAvatar">
Selected: {{ selectedAvatar.title }}
</div>
</div>
<!-- Banner file selector -->
<div>
<button @click="showBannerDrawer = true">
Select Banner
</button>
<v-drawer-files
v-model:active="showBannerDrawer"
field="banner"
folder="<banners-folder-id>"
:filter="imageFilter"
@input="handleBannerSelect"
/>
<div v-if="selectedBanner">
Selected: {{ selectedBanner.title }}
</div>
</div>
</div>
</template>
State Management
The component uses Vue's useSessionStorage composable to persist the user's navigation state during their session:
- Scoped by context: Each combination of
collection,field, andfoldergets its own storage key, preventing state collisions. - Automatic persistence: When users navigate to different folders, the state is automatically saved.
- Session-based: State persists across component remounting but clears when the browser session ends.
Events
The component emits an input event when files are selected:
TypeScript
@input="(files: any[]) => void"
The event payload is an array of selected file objects, each containing properties like id, title, type, and modified_on.
Practical Use Cases
1. User Profile Avatar Selection:
<v-drawer-files
v-model:active="selectingAvatar"
field="avatar"
@input="(files) => user.avatar_id = files[0].id"
/>
2. Multiple File Selection Dialog:
<v-drawer-files
v-model:active="selectingDocuments"
field="documents"
multiple
@input="(files) => documents.push(...files)"
/>