Search⌘ K
AI Features

Overview of Stencil

Explore Stencil as a compiler tool to create reusable, standards-based web components using Virtual DOM, reactive data binding, JSX, and TypeScript. Understand its benefits for performance, encapsulation, and cross-framework compatibility.

What is Stencil?

Stencil is a compiler tool developed by the team at Ionic specifically for the generation of standards-based Web Components and has been used since Ionic 4 for the creation of all their UI components.

For those who are new to Web Components, these are self-contained bundles of HTML, JavaScript/TypeScript, and CSS that are encapsulated away from the main code of our applications to create reusable widgets and components.

Web Components can be developed this way through the use of the following APIs and standards:

  • Custom Elements: A set of JavaScript APIs that developers can utilize to generate custom HTML elements and define their respective behaviors
  • Shadow DOM: A set of JavaScript APIs that allow for the creation of a “shadow” DOM tree (one that is entirely separate from the main DOM), which allows for features to be self-encapsulated. In other words, this means they are not able to affect or be affected by other parts of the main DOM tree
  • HTML Templates: Reusable chunks of HTML can be defined through the <template> and <slot> elements, allowing them to be used in conjunction with the Custom Elements API
  • Modules: Defines how JavaScript modules can be imported or reused in a standards-based, performant manner

Benefits of using Web Components

The benefits of using Web Components within our applications are as follows:

  • Code is self-contained thanks to the Shadow DOM. Nothing leaks out or in.
  • There is reusable logic and functionality, allowing us to build once and use that many times in many places.
  • They are dependency-free (unless legacy browser support is required, in which case polyfills may be needed).
  • The allow the creation of custom design systems and in-house component libraries.
  • Cutting edge features like Virtual DOM rendering, async rendering, and so on.
  • They are framework agnostic, meaning that they can be used with any framework or with plain JavaScript.

These are all pretty huge selling points for developers and development teams looking to create highly performant, scalable applications. Still, when it comes to web technologies, we have to ask the question—what is the level of browser support?

Browser support

When it comes to Web Components, support is generally okay (if the planned suppert isn’t for Internet Explorer, that is):

Browser Support for Web Components

Browser

Version

Internet Explorer

None

Edge

17+ (partial support)

Chrome

49+

Firefox

60+ (partial support)

Safari

11.1 (partial support)

iOS

10.3+ (partial support)

Android Chrome

67+

Fortunately, Stencil provides browser support for the following:

  • Chrome 60+
  • Safari 10.1+
  • Firefox 63+
  • Edge 79+
  • Internet Explorer 11 (via polyfill support)
  • Edge 16-18 (via polyfill support)

For the vast majority of usage cases, this should be more than sufficient, unless we still have to support IE6. If this is the case, then all we can say is good luck!

Community

Unsurprisingly, Web Components, given their huge upsides, have become increasingly used within the development community over the past two to three years, and many libraries, compilers, and authoring tools have been created to facilitate their use, such as:

  • Google Polymer
  • SlimJS
  • X-Tag
  • LitElement
  • Hybrids

So what exactly does Stencil bring to the table in terms of features and benefits? Why should a developer consider using that particular toolchain in their projects?

The Stencil stack

Stencil uses the following technologies and tools to generate standards-compliant Web Components:

  • Virtual DOM
  • Reactive data binding
  • Async rendering
  • JSX
  • TypeScript
  • Static Site Generation

Let’s look at each of these in a little more detail to gain a fuller appreciation of their benefits to developers.

Virtual DOM

The virtual DOM is a lightweight representation of an actual DOM object existing purely in memory. When state changes within the application occur, the virtual DOM is updated, and the previous and current states of the virtual DOM are compared.

As this is taking place, nothing is actually being drawn to the screen, making the virtual DOM updates and state comparisons quite speedy and optimized.

This comparison process, called diffing, determines if there are actual changes that have taken place. If there are, they then need to be updated within the actual DOM.

This process of managing changes within the virtual DOM ensures that only those objects that have been changed within the virtual DOM are updated in the real DOM, keeping any browser reflows and repaints to the absolute minimum required.

Doing so helps improve the speed and performance of an application.

Reactive data binding

Reactive data binding is a term used to describe the automatic updating of a component view with changes that have taken place to the underlying data.

This removes the onus on the developer to manage the rendering of those changes and makes an application feel snappier to the end-user.

Async rendering

Asynchronous rendering is a non-blocking process, which means that our application pages will continue to be loaded and rendered independently of the time taken for requested data or components to load.

This avoids the application “freezing” that can often occur with “heavier” items during synchronous rendering (a process that loads the content according to the order in which the browser has retrieved them).

JSX

JSX is a JavaScript language extension that brings XML-like syntax ability to JavaScript, allowing DOM nodes to be constructed from within the code. It is borrowed from the React ecosystem.

With JSX, a render function is used to help output a component tree of HTML nodes that will be rendered to the DOM at runtime. A sample JSX snippet of code might look something like the following:

JavaScript (JSX)
render() {
return (
<Host>
<img src={ this.image } />
<h2>{ this.title }</h2>
<button onClick={ () => this.imageSelected() }>More information</button>
</Host>
);
}

Notice how the component tree is typed as regular HTML but uses data bindings for rendering dynamic data for the heading and images values?

Similar to what we have experienced with Angular, we can trigger methods from event handlers placed on the HTML code in addition to data bindings (in the above example, a <button> element).

Our component tree is wrapped within a <Host> tag, a virtual component that references the host element (the actual tag that the rendered component will produce) but is never directly rendered to the DOM itself. We’ll be diving further into JSX a little later in this chapter.

TypeScript

Unsurprisingly, Stencil uses this superset of JavaScript, which adds class-based object-oriented programming with stronger typing to write our components with (and helps to ensure better-structured code with tighter “contracts” between supplied or shared data).

Static Site Generation

Unlike server-side rendering (SSR) or client-side rendering, Static Site Generation (SSG) is a build-time approach (pre-rendering) for building and rendering components and application routes.

Since routes and components are pre-rendered, that content is immediately available to both clients and search engines. This results in better performance and improvements for SEO as well as faster times to Largest Contentful Paint (LCP).