Editing Component Templates

When you open up a component, you'll see a file that cointains some HTML. This is the component's template. When TalkJS displays a component, it takes the data to be displayed, passes it to your template, and renders the resulting HTML. On this page, we'll guide you through everything you need to know to edit components.

The HTML structure of a component

At the top level, a component must always contain exactly 2 tags:

  • a <template> tag containing the HTML that'll be rendered to display this component
  • a <style> tag that contains the CSS for this component. You can put almost any CSS within the style tag, and we'll ensure that it gets applied to your component's HTML.

It's important that HTML tags in your template are always closed correctly. Even tags like <img> that usually don't have a closing tag should be written in a self-closing way, like <img/>.

Using data in your templates

Your component template receives a set of variables that you can use. To include a variable, enclose it in {{ and }}. So for example, if your component receives a variable called message, to output it, you'd write {{ message }}. Variables can hold objects that contain other fields. To access a field, you use the dot . notation, like {{ user.name }}.

You can use these in the contents of elements, but also in attribute values. Take this for example:

1<div class="message {{ message.type }}">{{ message.body.text }}</div>

If your message type is "text", the resulting HTML will look like this:

1<div class="message text">message content</div>

Transforming data using filters

There are sometimes changes you'd like to make to data before displaying it, and filters are the right tool for the job. You can see the list of available filters in our template language reference. To apply a filter to a value, add a pipe character (|), followed by the name of the filter you'd like to use. For example, to output the value of name in upper case, you'd write

1{{ name | upcase }}

Most filters also take a parameter. For example, the prepend filter takes a string to prepend to its input. Here's how to use it:

1{{ name | prepend: "Hello " }}

Rendering conditionally

Sometimes, you want to display different data in different cases. The easiest way to do that is the t:if attribute. If it is present on an element, that element will only be rendered if its element is truthy. The t: prefix is our way to indicate that an attribute is part of the TalkJS template language. Let's look at an example:

1<span t:if="{{ conversation.participants.length > 2 }}">
2 {{ sender.name }}

If you want to render something different if the conditional doesn't apply, you use t:else. The elements with t:if and t:else should be directly next to each other in your template, like this:

1<img t:if="{{ user.photoUrl }}" src="{{ user.photoUrl }}" class="avatar" />
2<div t:else class="fake-avatar"></div>

Similar to many programming languages, the language also support checking for multiple conditions to render different things with t:else-if.

1<div t:if="{{ condition1 }}"></div>
2<div t:else-if="{{ condition2 }}"></div>

It acts as a combination of t:else and t:if, so it is only rendered if the previous t:if element was not rendered, and the expression in the attribute value is truthy.

If you'd like to do the same within an expression, we have some special filters. Take a look at this

1<div class="message {{ sender.role == 'admin' | then: 'by-admin' }}"></div>

This will give this element a by-admin class, but only if `sender.role == "admin". In general, if the value to the left of the pipe is truthy, this filter returns its argument. If not, it'll return nil, and nothing will be rendered.

There's also an else filter that you can chain with the if to produce expressions like this

2 class="message {{ sender.role == 'admin' | then: 'by-admin' | else: 'non-admin' }}"
4 ...

When the value on the left of | else is falsy, this value returns its argument. Otherwise, it just passes on what it received from the left.

These are all the tools that are used in our components. You can find a reference of all the directives and filters in the TalkJS template language reference.


The <style> element only lets you style the HTML that's in the <template> element. It's scoped to the current component, which means you can't use it to inject CSS that applies outside the current component.

We recommend using classes to apply styling. Do not use element selectors or ID selectors, as they might not work properly and future TalkJS updates may change or break their behavior.

Otherwise, you ought to be able to use pretty much any CSS. The themes engine does some post-processing on your CSS as described in the next section.

Differences between templates and browser Developer Tools

If you use your browser's Developer Tools to inspect the themed chat UI, you may notice some subtle differences.

For CSS code:

  • We prepend the component name to all CSS class names. For example, a class author in the UserMessage component will show up as UserMessage__author in devtools. This effectively scopes all CSS to that component1.
  • If you define CSS variables on the :root pseudo-class (which applies to the entire page), then all uses of these properties are replaced by their values. This lets you use CSS variables and still support old browsers.
  • calc(..) expressions with constant values are computed and replaced by their results. So calc(5px + 6px) becomes calc(11px).

For HTML code:

  • Tags and attributes that could create security issues (<script>, onclick etc) are removed.
  • All special template attributes (such as t:if) are removed.

Note that we intend to add secure support for onclick and friends in the future.

  1. This is by design, as it allows the TalkJS team to ship fixes and improvements to the chat UI code structure without breaking compatibility with your designs.