Skip to main content
Version: v3.0

Working with host elements

Stencil components render their children declaratively in their render method using JSX. Most of the time, the render() function describes the children elements that are about to be rendered, but it can also be used to render attributes of the host element itself.

<Host>

The Host functional component can be used at the root of the render function to set attributes and event listeners to the host element itself. This works just like any other JSX:

// Host is imported from '@stencil/core'
import { Component, Host, h } from '@stencil/core';

@Component({tag: 'todo-list'})
export class TodoList {
@Prop() open = false;
render() {
return (
<Host
aria-hidden={this.open ? 'false' : 'true'}
class={{
'todo-list': true,
'is-open': this.open
}}
/>
)
}
}

If this.open === true, it will render:

<todo-list class="todo-list is-open" aria-hidden="false"></todo-list>

similarly, if this.open === false:

<todo-list class="todo-list" aria-hidden="true"></todo-list>

<Host> is a virtual component, a virtual API exposed by stencil to declaratively set the attributes of the host element, it will never be rendered in the DOM, i.e. you will never see <Host> in Chrome Dev Tools for instance.

<Host> can work as a <Fragment>

<Host> can also be used when more than one component needs to be rendered at the root level for example:

It could be achieved by a render() method like this:

@Component({tag: 'my-cmp'})
export class MyCmp {
render() {
return (
<Host>
<h1>Title</h1>
<p>Message</p>
</Host>
);
}
}

This JSX would render the following HTML:

<my-cmp>
<h1>Title</h1>
<p>Message</p>
</my-cmp>

Even if we don't use <Host> to render any attribute in the host element, it's a useful API to render many elements at the root level.

Element Decorator

The @Element() decorator is how to get access to the host element within the class instance. This returns an instance of an HTMLElement, so standard DOM methods/events can be used here.

import { Element } from '@stencil/core';

...
export class TodoList {

@Element() el: HTMLElement;

getListHeight(): number {
return this.el.getBoundingClientRect().height;
}
}

In order to reference the host element when initializing a class member you'll need to use TypeScript's definite assignment assertion modifier to avoid a type error:

import { Element } from '@stencil/core';

...
export class TodoList {

@Element() el!: HTMLElement;

private listHeight = this.el.getBoundingClientRect().height;
}

If you need to update the host element in response to prop or state changes, you should do so in the render() method using the <Host> element.

Styling

See full information about styling on the Styling page.

CSS can be applied to the <Host> element by using its component tag defined in the @Component decorator.

@Component({
tag: 'my-cmp',
styleUrl: 'my-cmp.css'
})
...

my-cmp.css:

my-cmp {
width: 100px;
}

Shadow DOM

Something to beware of is that Styling the <Host> element when using shadow DOM does not work quite the same. Instead of using the my-cmp element selector you must use :host.

@Component({
tag: 'my-cmp',
styleUrl: 'my-cmp.css',
shadow: true
})
...

my-cmp.css:

:host {
width: 100px;
}