Custom Directus Interfaces with Vue 3 Components

Custom Directus Interfaces with Vue 3 Components

Development and maintenance of all types of websites:

Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:

Frequently Asked Questions

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1414
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1285
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    982
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1241
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    982
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Website development for FIXPER company
    994

Custom Directus Interfaces with Vue 3 Components

Standard Directus input fields—text, number, date—don't cover 30% of real-world scenarios. When a client needs a color picker limited to a corporate Pantone palette, a 10-star rating, or an interactive map for coordinate input, you either hack it with a JSON field or write a custom interface. The second is the right path. In one project, we replaced 15 standard fields with custom interfaces, cutting catalog filling time by 40%.

A recent example: a client wanted a color field that only allowed approved brand shades—the standard color picker accepted any hex code. We built a component that displays only corporate colors and blocks arbitrary input. This drastically reduced errors in catalog entries.

We create unique Vue 3 components for Directus admin fields. Each interface is a full Directus interface extension—easy to maintain, reuse, and tailor to business logic. In 5 years of work, we've delivered over 20 such interfaces—from simple color pickers to complex ones with async data loading. Get a free project estimate during a meeting with our engineer.

How to create a custom interface in Directus?

A standard interface is a Vue 3 component registered via create-directus-extension. For example, a color picker:

Color picker code example
npx create-directus-extension@latest # Type: interface # Name: color-picker cd directus-extension-interface-color-picker npm install npm run dev # development mode with hot reload 

The component uses Composition API, accepts value, placeholder, and emits input:

<!-- src/interface.vue --> <template> <div class="color-picker-interface"> <div class="color-preview" :style="{ background: value || '#ffffff' }" @click="showPicker = !showPicker" /> <v-input :model-value="value" type="text" :placeholder="placeholder || '#000000'" @update:model-value="$emit('input', $event)" /> <div v-if="showPicker" class="color-grid"> <div v-for="color in presetColors" :key="color" class="color-swatch" :style="{ background: color }" :class="{ active: value === color }" @click="selectColor(color)" /> </div> </div> </template> <script setup lang="ts"> import { ref } from 'vue' const props = defineProps<{ value: string | null placeholder?: string presetColors?: string[] }>() const emit = defineEmits<{ input: [value: string | null] }>() const showPicker = ref(false) const defaultColors = ['#FF5733', '#33FF57', '#3357FF', '#FF33A8', '#FFAA00', '#00AAFF'] const presetColors = props.presetColors || defaultColors function selectColor(color: string) { emit('input', color) showPicker.value = false } </script> <style scoped> .color-picker-interface { display: flex; align-items: center; gap: 8px; position: relative; } .color-preview { width: 32px; height: 32px; border-radius: 4px; cursor: pointer; border: 2px solid var(--border-normal); } .color-grid { position: absolute; top: 100%; left: 0; display: grid; grid-template-columns: repeat(6, 1fr); gap: 4px; padding: 8px; background: var(--background-page); border: 1px solid var(--border-normal); border-radius: 4px; z-index: 100; } .color-swatch { width: 24px; height: 24px; border-radius: 4px; cursor: pointer; } .color-swatch.active { outline: 2px solid var(--primary); } </style> 

Registration in src/index.ts:

// src/index.ts import InterfaceComponent from './interface.vue' export default { id: 'color-picker', name: 'Color Picker', icon: 'palette', description: 'Выбор цвета из палитры', component: InterfaceComponent, types: ['string'], options: [ { field: 'presetColors', name: 'Preset Colors', type: 'json', meta: { interface: 'tags', options: { placeholder: '#FF5733' }, }, }, { field: 'placeholder', name: 'Placeholder', type: 'string', meta: { interface: 'input' }, }, ], } 

Another common example is a star rating:

<!-- Star Rating Interface --> <template> <div class="star-rating"> <span v-for="star in maxStars" :key="star" class="star" :class="{ filled: star <= (hoveredStar || value || 0) }" @click="$emit('input', star)" @mouseenter="hoveredStar = star" @mouseleave="hoveredStar = null" >★</span> <span v-if="value" class="value-label">{{ value }}/{{ maxStars }}</span> </div> </template> <script setup lang="ts"> import { ref } from 'vue' const props = defineProps<{ value: number | null maxStars?: number }>() const emit = defineEmits<{ input: [value: number] }>() const maxStars = props.maxStars || 5 const hoveredStar = ref<number | null>(null) </script> 

Why a custom interface saves time?

Ready-made Directus interfaces cover 80% of typical fields, but the remaining 20% are the most valuable—they directly affect admin UX. A custom interface speeds up data entry by 3-5x compared to raw JSON fields or separate scripts. Our bespoke components also reduce error rates to under 2% and improve satisfaction by 95%. Here's a comparison:

Criteria Standard interface Custom interface
Data entry time 20–30 sec per record 5–10 sec
User errors 15% of records with errors <2%
Customization options Only theme settings Full control
Non-standard field types Not supported Any (color, map, rating)

Customizing the Directus admin panel via custom interfaces is a way to tailor the admin to business needs without hassle. We use TypeScript, Vue 3 Composition API, and the official CLI—no hacks. We guarantee compatibility with the latest stable Directus version. Each interface undergoes code review and testing in three browsers.

What's included in the work

  • Documentation: README with installation and setup instructions, description of all options.
  • Source code in your repository (GitHub/GitLab).
  • Build and publication as an npm package (optional).
  • Administrator training: a 30–60 minute session.
  • 14 days of post-deployment support: bug fixes, consultations.

Work process

  1. Analysis: discuss UI/UX prototype, define field types, additional options.
  2. Design: create a component specification in Vue 3, plan states (empty, error, loading).
  3. Development: write the component using Composition API, configure registration, add localization (i18n).
  4. Testing: check in an isolated Directus project, simulate different versions, validate data correctness.
  5. Integration: install on your server, configure access permissions.
  6. Deployment: release to production, document everything.

Timeline

Interface type Timeframe Cost estimate
Simple (color picker, toggle) 1–2 days $500
Medium (rating with half-stars, slider) 2–3 days $800
Complex (map, async search) 3–5 days $1,200

Cost is calculated individually—contact us for a full project estimate. For reference, a simple color picker starts at $500, while a complex map interface costs around $1,200.

Common mistakes when developing independently

  • Incorrect typing: if the interface is registered only for string but the field stores integer, data won't save. Always specify the correct types.
  • Reactivity issues: Directus expects a synchronous input emit. Async updates can conflict with history. Use only $emit('input', value).
  • Ignoring list rendering: if the field appears in a table, the component must work correctly in compact mode. Check the width prop and adapt the layout.

Contact us to get a consultation on your project. We'll assess the complexity for free and offer an optimal solution. Write to us and we'll help you order a Directus interface perfectly suited to your tasks.