Developing Custom Displays in Directus
Display Extension is a Vue 3 component for displaying field values in the collection view and preview form. When standard displays (raw, datetime, boolean, related-values) don't suit your needs, a custom display is created.
When Custom Display Is Needed
- Show a colored circle for a
colorfield instead of HEX string - Render a progress bar for a numeric
progressfield - Display a status icon instead of text
- Format complex JSON data as a table
Basic Display
npx create-directus-extension@latest
# Type: display
# Name: color-display
<!-- src/display.vue -->
<template>
<div class="color-display">
<div
v-if="value"
class="color-swatch"
:style="{ background: value }"
/>
<span class="color-value">{{ value || '—' }}</span>
</div>
</template>
<script setup lang="ts">
defineProps<{ value: string | null }>()
</script>
<style scoped>
.color-display { display: flex; align-items: center; gap: 6px; }
.color-swatch { width: 16px; height: 16px; border-radius: 3px; border: 1px solid rgba(0,0,0,0.1); flex-shrink: 0; }
.color-value { font-size: 12px; font-family: monospace; }
</style>
// src/index.ts
import DisplayComponent from './display.vue'
export default {
id: 'color-display',
name: 'Color Swatch',
icon: 'palette',
description: 'Shows color as a colored circle',
component: DisplayComponent,
types: ['string'],
options: null, // no additional settings
}
Status Display with Icon
<template>
<div class="status-display" :class="`status-${value}`">
<v-icon :name="statusConfig[value]?.icon || 'circle'" small />
<span>{{ statusConfig[value]?.label || value }}</span>
</div>
</template>
<script setup lang="ts">
defineProps<{ value: string | null }>()
const statusConfig: Record<string, { icon: string; label: string }> = {
draft: { icon: 'edit', label: 'Draft' },
review: { icon: 'visibility', label: 'In Review' },
published: { icon: 'check_circle', label: 'Published' },
archived: { icon: 'archive', label: 'Archive' },
}
</script>
<style scoped>
.status-display { display: flex; align-items: center; gap: 4px; font-size: 12px; }
.status-published { color: var(--success); }
.status-draft { color: var(--warning); }
.status-archived { color: var(--foreground-subdued); }
</style>
Progress Display
<template>
<div class="progress-display">
<div class="progress-bar">
<div class="progress-fill" :style="{ width: `${percentage}%`, background: color }" />
</div>
<span class="progress-label">{{ value }}{{ suffix }}</span>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
const props = defineProps<{
value: number | null
maxValue?: number
suffix?: string
}>()
const percentage = computed(() =>
Math.min(100, ((props.value || 0) / (props.maxValue || 100)) * 100)
)
const color = computed(() =>
percentage.value >= 80 ? '#4CAF50' : percentage.value >= 50 ? '#FF9800' : '#F44336'
)
</script>
// Registration with options
export default {
id: 'progress-display',
name: 'Progress Bar',
icon: 'linear_scale',
component: DisplayComponent,
types: ['integer', 'float', 'decimal'],
options: [
{
field: 'maxValue',
name: 'Max Value',
type: 'integer',
meta: { interface: 'input', default_value: 100 },
},
{
field: 'suffix',
name: 'Suffix',
type: 'string',
meta: { interface: 'input', options: { placeholder: '%' } },
},
],
}
Attaching Display to a Field
In Settings → Data Model → field → Interface & Display → select Display = Color Swatch or Progress Bar.
Timeline
Development of 2–3 custom displays — 1 day.







