Customizing elements

You can extensively customize Elix elements for the context of your application. There are several techniques for doing this:


Most Elix elements accept content via their default slot. Some complex elements have multiple slots. E.g., Carousel defines slots inside its left and right arrow buttons. You can fill those slots with custom arrow icons or other content:

  <div slot="arrowButtonLeft">↫</div>
  <div slot="arrowButtonRight">↬</div>
  <img src="image01.jpg">
  <img src="image02.jpg">
  <img src="image03.jpg">
  <img src="image04.jpg">
  <img src="image05.jpg">

The custom icons are shown inside the arrow buttons:

Mountain lake Terraced farm Winter trees Forest river Red panda
Demo: Carousel with custom arrow button icons


When the state of an Elix element changes, it uses a mixin called RenderUpdatesMixin to determine what updates should be applied to the element host and the elements in its shadow tree. The mixin accomplishes this by asking the element for the current value of its updates property.

This system allows for the appearance and behavior of an element to be collectively defined by the element class, its base classes, and any mixins applied to it. You can tap into this system by subclassing an Elix element and defining an updates property that sets styles and other properties on the element or its subelements.

Element roles

Complex Elix elements like Carousel and Tabs have templates with various key subelements. Such complex elements expose properties you can set to determine what standard or custom HTML elements are used to fill key roles in the template.

E.g., Carousel has a key element role called the "stage", which shows a single selected item (usually an image) at a large size. Carousel also defined another role called the "proxy" for the element that will be used to represent a specific item; by default, the proxy is a small PageDot.

You can override these roles on an element-by-element basis by setting role properties on the element in markup or before the component is attached to the DOM. Element roles are filled by supplying a descriptor that is either:

  • A component class (FooElement) that will be instantiated to fill the role.
  • A string representing the tag name ("foo-element") that will be instantiated to fill the role.
  • An HTMLTemplateElement that will be cloned to the fill the role.

Example: if you have a defined your own custom elements for a carousel's arrow buttons and page dots, you could use those with a specific Elix Carousel. You could instantiate the Carousel in markup, then fill the role by setting properties for the element's arrowButtonRole and proxyRole. In the case of markup, this can be done by identifying the tag name for the desired custom elements:

<script type="module" src="node_modules/elix/src/Carousel.js"></script>
<script type="module" src="MyArrowButton.js"></script>
<script type="module" src="MyPageDot.js"></script>

  <elix-carousel arrow-button-role="my-arrow-button" proxy-role="my-page-dot">
    <img src="image1.jpg">
    <img src="image2.jpg">
    <img src="image3.jpg">

By specifying what standard or custom element should be used for that key subelements, you can provide arbitrary customizations of the Carousel's appearance and behavior.

You can also define roles on a class basis. Suppose you want to create a custom carousel that always uses your custom page dot to represent the items in the carousel. You can do this in the constructor by setting the symbols.roles property:

import Carousel from 'elix/src/Carousel.js';
import MyArrowButton from 'MyArrowButton.js';
import MyPageDot from 'MyPageDot.js';

class MyCarousel extends Carousel {
  constructor() {
    this[symbols.roles] = Object.assign({}, this[symbols.roles], {
      arrowButton: MyArrowButton,
      proxy: MyPageDot

The result has all the functionality of the base Carousel, with the customized appearance of the arrows and page dots:

Mountain lake Terraced farm Winter trees Forest river Red panda
Demo: Carousel with custom arrow buttons and page dots

You can create some fairly unusual combinations of components with this role technique. For example, the following customized AutoCompleteComboBox uses a Carousel to fill its list role, which is normally filled by a ListBox:

Mountain lake Terraced farm Winter trees Forest river Red panda
Demo: A combo box with a carousel inside it

This isn't to say that this particular combination is a great idea, but rather that such combinations are possible and largely work as expected. Here, the carousel's swiping behavior work as expected, as does the input area's auto-completion. The rigorous testing criteria for Elix components, including those in the Gold Standard Checklist for Web Components, help make such combinations work predictably.

Template patching

Many Elix elements are specializations of other types of elements. Often such relationships are expressed in a class hierarchy. For example, a DropdownList is a specialized type of MenuButton, so DropdownList is defined as a subclass as MenuButton. MenuButton is in turn is a special type of PopupSource, and again the former is defined as a subclass of the latter.

Such specialized classes often need to add additional elements to the template defined by their parent classes. A common Elix pattern is to have a component define its template by obtaining a template from its parent class, then patching the result to define its own template. This is often done using helper functions in the template module.

Appending an additional stylesheet

One particularly common form of template patching is having a subclass append an additional stylesheet to the template defined by the base class. This has the benefit of simplicity, and ensures the subclass' desired styles can cleanly override styles defined by the base class — since the subclass's appended stylesheet comes after any stylesheet(s) defined by the base class.

See template.concat for an example.

Reusing mixins

Sometimes you want to create a component that's substantially similar to an existing Elix element, but which is different enough that the techniques above are insufficient. In such cases, you may still be able to reuse much of the code for the Elix element in question by creating your own component from the same set of mixins.

The vast majority of the behavior for all Elix elements is defined by mixins. The documentation for each element will indicate what mixins it uses; inspecting the source code is obviously helpful as well. Having identified that set of mixins, you can apply that same set of mixins to a base class like HTMLElement or ReactiveElement to create a fundamentally new component that nevertheless reuses a considerable degree of code. This allows you to both create components more quickly, and at a higher degree of quality.