How to Create a Custom Interface

Directus comes loaded with many awesome interfaces for you to use out-of-the-box, from color pickers to full-featured WYSIWYG editors. On top of that, Directus provides a modular system to extend the admin app with your own interfaces. This powerful tool allows you to create interfaces which can modify your data in any way you see fit. In this article, we will deep-dive into creating such an interface by taking a step-by-step look at the rating interface, which is included in every instance of core Directus.

The Main Boilerplate

To keep each interface neatly organized, it’s code is typically split into three main files. This separation can be found in every core interface (/app/core/interfaces) as well as all custom interfaces (/customs/interfaces).

├── component.js
├── input.html
└── interface.js

About the rating interface

The rating interface shows n number of stars — as defined by the max_score option — and allows users to save ratings by clicking on a star.

Screenshot of the rating interface


The component (component.js) contains the metadata — like id, supported datatypes, and options — of the interface and connects the interface-controller (interface.js) to the view ( input.html).

The component.js file of the rating interface looks like this:

As you can see, there are 6 main things defined in the component. From top to bottom:

  • id: the unique ID of this interface. This is also the name it gets when shown in the settings pane. It is comprised of numbers, lowercase letters, and underscores.
  • dataTypes: an array of supported MySQL datatypes.
  • variables: the supported options of this interface. Each option is an object which itself contains the options of the particular interface used for the option. So meta! An option object usually looks something like this:
// Name of the option
id: 'read_only',
  // Interface used for this option  
ui: 'toggle',
  // Type of data expected
type: 'Boolean',
  // Instructions for this option
comment: 'Force this interface to be read only',

// The default value for this option
default_value: false
  • Input: the reference to the interface controller (imported by RequireJS from ./interface.
  • validate: a callback function which will fire on save. Allows you to plug in custom validation logic. Returning a string will show the string in a warning message box to the user. Returning undefined or null will continue the saving process without interruption.
  • list: a callback function which allows you to override the default output (the raw value) which is shown on the item listing page. This needs to return either a value or a string of HTML.


The interface.js file is responsible for passing data through to the template (input.html) and handling changes in said template. In practice, this setup looks like this:

This model only requires two fields to be set to function properly:

  • template: the path to the template file (input.html).
  • serialize: the main function which returns the data that is being sent to the Handlebars template file.

In this case, the interface file sends four different pieces of data to the template file: the currently saved value, the number of stars allowed by the max_score option, and the name of the interface.

Since the rating interface uses styled radio buttons as input, it already has a place to keep track of the actual value (the radio input itself). However, if you needed to alter the value on change, you can use events. Checkout the _example boilerplate (custom interfaces and extensions with a leading underscore are ignored) for a demo on how to do this.

Input (template file)

The template file might be the most straightforward part of the whole setup. It only has to render the actual user interface to screen, which most of the times is some sort of input and some styling. For the rating interface, this is:

In this particular case, the template renders n amount of inputs based on the max_score setting. The most important thing to note about the template is the fact that the name attribute of the input (if applicable) is unique, otherwise it could conflict with other inputs on the page.

That’s it! This is all you need to get started with your own custom interfaces to use with Directus.

Which existing interfaces do you love the most? What amazing custom interface are you going to build? We’d love to know in the comments below!

Happy coding!

Your friends at Directus