Templates

There are 3 ways one can customize the DOM structure of a UI Component:

  1. Many components expose a ConversationViewreplaceableContent property that allows you to customize specific areas of each UI Component. This is by far the easiest and most practical way to customize components such as Message Items, Conversation Items, Conversation Panels, etc; see Conversation View for examples.
  2. Most components have a Template that represents its DOM structure; you may override this with your own template. See below for details.
  3. Custom Javascript may be written to customize DOM structures at run time; see Modifying Components.

To illustrate how one might customize a template, this example illustrates how to customize the way a Conversation Item is rendered in the Conversation List. The task: remove last_message, and add the participant’s status in its place.

  • The buildStyle method is used to replace a Component’s built-in styles.
  • The buildAndRegisterTemplate method is used to replace the DOM structure for the Component’s template.
Layer.UI.buildStyle('layer-conversation-item', `
  layer-conversation-item {
    display: block;
  }
`);
Layer.UI.buildAndRegisterTemplate('layer-conversation-item', `
  <div class='layer-list-item' layer-id='innerNode'>
    <layer-replaceable-content  class='layer-conversation-left-side' name='conversationRowLeftSide'>
    </layer-replaceable-content>

    <div class='layer-conversation-item-content'>
      <div class='layer-conversation-title-row'>
        <layer-conversation-title layer-id='title'></layer-conversation-title>
        <layer-date layer-id='date'></layer-date>
      </div>
      <!-- REMOVE LAST MESSAGE FOR THIS EXAMPLE
      <layer-conversation-last-message layer-id='lastMessage'></layer-conversation-last-message>
      -->

      <!-- ADD CUSTOM NODE FOR THIS EXAMPLE: -->
      <my-custom-participant-status layer-id='participantStatus'></my-custom-participant-status>
    </div>

    <layer-replaceable-content  class='layer-conversation-right-side' name='conversationRowRightSide'>
    </layer-replaceable-content>
  </div>
`);

Making Templates Flexible with Replaceable Content

Replaceable Content is how the Layer XDK provides Slots which are a part of Webcomponents that depends upon Shadow DOM which is not well supported cross browser. It provides to define a UI Component that has regions that can be populated with DOM nodes coming from outside of the UI Component’s definition. The above template definition registers a Replaceable Content named conversationRowRightSide and another one named conversationRowLeftSide which will accept any DOM structures provided it during initialization using:

var conversationItem = document.createElement('layer-conversation-item');
conversationItem.replaceableContent = {
  conversationRowLeftSide: '<layer-menu-button node-id="menuButton"></layer-menu-button>',
  conversationRowRightSide: function(widget) {
    var div = document.createElement('div');
    var avatar = document.createElement('layer-avatar');
    var menu = document.createElement('layer-menu-button');
    div.appendChild(avatar);
    div.appendChild(menu);
    return div;
  }
};

When replacing a UI Component’s template, please make sure that:

  1. The customizations you intend to make are to areas that don’t already have a Replaceable Content node ready for you to customize its behaviors
  2. Any Replaceable Content nodes from the original definition should (but not must) be included in your redefined template; removing these removes your ability to customize these components on demand.

You can see the template of any UI Component you want to replace by:

  1. Opening the docs for the [UI Component](API_REFERENCE#!/api/Layer.UI.components.ConversationView]
  2. Mouse over the title naming the class you are looking at (this will cause a View Source… link to show)
  3. Click the View Source… link
  4. Search the source file for template: to find the template definition (which may need to be copied/pasted to a place where you can format it more readably)

The layer-id Attribute

The layer-id attribute assigns a name to the DOM node that allows the widget to directly reference it. By having layer-id="avatar", we have told the widget to setup the property widget.nodes.avatar to refer to the layer-avatar node. By adding layer-id='dateWidget' we have made it so we can use widget.nodes.dateWidget to access the date widget.

The template property shown below will allow our class to access the date, title and innerNode nodes as early as the onCreate method of the Component Lifecycle:

layer.UI.registerComponent('my-sample-widget', {
  template: `
    <div layer-id='innerNode'>
      <layer-avatar layer-id='avatar'></layer-avatar>
      <div layer-id='title'></div>
    </div>
    <layer-date layer-id='dateWidget'></layer-date>
  `,
  methods: {
    onCreate() {
      this.nodes.innerNode.addEventListener('onmouseover', this.onMouseOver.bind(this));
      this.nodes.avatar.users = [client.user];
      this.nodes.dateWidget.date = new Date();
    }
  }
});

Safely Customizing Templates with Existing layer-id Nodes

Building a template for an existing Component requires you to know what layer-id names the widget expects to have available. Most widgets will test for the existence of the named item before using them, but you must insure that required ones have been defined in your html file. Its recommended that if you replace the component for an existing widget, that you start with a copy of the original template, adjust a few nodes at a time, and retest to make sure that no errors are thrown due to missing layer-id named nodes. You can also look at the code and find any reference to this.nodes.XXXX before removing a node with a layer-id="XXXX".

Template Styling

Each template within the file has its own optional style section. When designing your CSS rules, we recommend the following:

  1. Put basic layout CSS in the widget; in particular if using flex-box to layout the widget, that should be setup here
  2. Put Colors, Font, margin, border and padding all in your theme where it can be modified with other parts of your theme
  3. Put the minimum required CSS to make your widget function; the CSS for making your widget look good generally is part of your theme
  4. Always specify the display style for the Webcomponent in the styles section; a Webcomponent without a display will default to something that does not render well.

The Web XDK does not use Shadow DOM, therefore, you should prefix all of your CSS rules with the component name. If you are targeting .title in your rule, it should be my-sample-widget .title in your rule.

Layer.UI.buildStyle('my-sample-widget', `
  my-sample-widget {
    display: flex;
  }
  my-sample-widget > div {
    flex-grow: 1;
  }
  my-sample-widget > div + div {
    width: 50px;
  }
`);

Custom Templates for List Items

All List Items (MessageListPanel.SentItem, ConversationListPanel.Item.Conversation, IdentityListPanel.Item, etc…) have an item property representing the item of data within the list that they are rendering. They will pass this item to any node in their template that contains a layer-id. Example:

  <div class='layer-list-item' layer-id='innerNode'>`
    <my-custom-widget-1 layer-id='widget1'></my-custom-widget-1>
    <my-custom-widget-2 layer-id='widget2'></my-custom-widget-2>
    <my-custom-widget-3 layer-id='widget3'></my-custom-widget-3>
    <my-custom-widget-4></my-custom-widget-4>
  </div>

If you have defined Custom Components my-custom-widget-1 through my-custom-widget-4, and defined an item property for them, they should expect to have their item property set automatically… except for my-custom-widget-4 above which did not define a layer-id.

This means that there are certain types of template modifications you can make without requiring javascript changes to pass data to your new subcomponents.

Its also important to note that All List Items expect their templates to have everything contained within the following node: <div class='layer-list-item' layer-id='innerNode' />; this should be maintained in any template you make for any type of List Item.

Misc Components Theming