Marcus Hellberg

How to use Web Components

This tutorial teaches you how to use and interact with web components. We’ll build a small UI that adds people to a data grid.

The completed app: A form with two text fields for name and an add button for adding people to a data grid.

Most Web Components, like the Vaadin component set, are distributed as ES modules. To use them efficiently, you need to have a build tool like Webpack, Parcel, or Rollup.

If you already have an existing project that handles ES modules, feel free to skip directly to Step 1.

Step 0: Build tooling

Create and init project

Start by creating a new folder and initializing NPM in it.

$ mkdir webcomponents
$ cd webcomponents
$ npm init -y (1)
  1. The -y flag answers yes to all NPM init questions by default. If you want to customize the answers, omit this.

Then, install Webpack and plugins:

$ npm install --save-dev webpack webpack-dev-server webpack-cli html-webpack-plugin

Project structure

Inside the webcomponents directory that you created, create another folder: src. Inside of it, create index.html, and index.js.

Leave index.js empty for now. Add the following to index.html:

src/index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Webcomponents!</title>
  </head>
  <body>
    Yay!
  </body>
</html>

Configure Webpack

In the root of the project, create a webpack configuration file webpack.config.js:

webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = ({ mode }) => {
  return {
    mode, (1)
    plugins: [
      new HtmlWebpackPlugin({
        template: './src/index.html' (2)
      })
    ],
    devtool: mode === 'development' ? 'source-map' : 'none' (3)
  };
};
  1. Configure the mode property. This will be set from the commandline and be either development or production.

  2. Tell HtmlWebpackPlugin to use our index file instead of generating its own.

  3. Enable sourcemaps for development

Add scripts for running the app

Define two NPM scripts in package.json for running and building the app.

"scripts": {
-    "test": "echo \"Error: no test specified\" && exit 1"
+    "dev": "webpack-dev-server --env.mode development",
+    "prod": "webpack --env.mode production"
  },

After this, you can start a development server with npm run dev or build a production optimized build with npm run prod.

Any changes you make to the source code are automatically compiled and reflected in the browser during development time.

Tip
This is a very barebones setup that works well for development. You will most likely need to expand on it for your own needs with things like transpilation. The Webpack documentation is an excellent place to continue learning about configuring the build.

Step 1: Using Web Components

Install the components

The first step in using web components is installing them. In this case, we install vaadin-text-field, vaadin-button, and vaadin-grid from the Vaadin component set. In addition to the components, we install webcomponentsjs, which is a polyfill for adding support to older browsers.

$ npm install --save @vaadin/vaadin-text-field @vaadin/vaadin-button @vaadin/vaadin-grid

Once the install finishes, import the components in index.js to make them available to your browser.

src/index.js
import '@vaadin/vaadin-button';
import '@vaadin/vaadin-grid';
import '@vaadin/vaadin-text-field';

Add polyfills for older browsers

Although most modern browsers ship with built-in support for Web Components, there are still users out there with older browsers. If you want to make your app available to them as well, you want to include polyfills that emulate the functionality in browsers without native support.

The webcomponents.js polyfill comes with a loader script that can be used to load only the polyfills a particular browser needs. It loads the polyfills dynamically, so it cannot be imported directly as a JS dependency that gets built by Webpack, rather you need to copy over the dependencies and include the loader in your index file. The library also includes a ES5 compatibility script in case you transpile your app into ES5.

$ npm install --save-dev copy-webpack-plugin @webcomponents/webcomponentsjs

Copy polyfills

The first thing we need to do is copy over the polyfills. If you are using a different build tool than Webpack, refer to the documentation for that tool on how to copy over static assets.

webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
+const CopyWebpackPlugin = require('copy-webpack-plugin');

module.exports = ({ mode }) => {
  return {
    mode,
    plugins: [
      new HtmlWebpackPlugin({
        template: './src/index.html'
      }),
+      new CopyWebpackPlugin([
+        {
+          context: 'node_modules/@webcomponents/webcomponentsjs',
+          from: '**/*.js',
+          to: 'webcomponents'
+        }
+      ])
+    ],
    devtool: mode === 'development' ? 'source-map' : 'none'
  };
};

Load polyfills

Then, include the loader and an optional import for the ES5 compatibility script in the <head> section of index.html.

src/index.html
<script src="webcomponents/webcomponents-loader.js"></script>
<script>
  if (!window.customElements) { document.write('<!--'); }
</script>
<script src="webcomponents/custom-elements-es5-adapter.js"></script>
<!-- ! DO NOT REMOVE THIS COMMENT, WE NEED ITS CLOSING MARKER -->

You are now ready to use web components in IE11+ and any of the evergreen browsers.

Use Web Components to build the UI

Once you have installed the components, you can use them like any other HTML tag. Replace the body contents of index.html with the following:

src/index.html
<div class="form">
  <vaadin-text-field label="First Name" id="firstName"> </vaadin-text-field>
  <vaadin-text-field label="Last Name" id="lastName"> </vaadin-text-field>
  <vaadin-button id="addButton"> Add </vaadin-button>
</div>
<vaadin-grid id="grid">
  <vaadin-grid-column path="firstName" header="First name"> (1)
  </vaadin-grid-column>
  <vaadin-grid-column path="lastName" header="Last name">
  </vaadin-grid-column>
</vaadin-grid>
  1. The grid uses an array of objects as its data source. The path attribute defines what property of that object should be shown in the column.

Notice that we added id attributes for all components. Ids make it easier for us to get hold of them from JavaScript in the next step.

Listen for events and update properties

Now that we have all the UI building blocks in place, the next step is to add some functionality.

Start by adding a load event listener in index.js that calls a function initUI().

src/index.js
window.addEventListener('load', () => {
  initUI();
});
Tip
With any JavaScript, it is an excellent practice to defer work until after the load event to allow the browser to render all static content before running JavaScript. Using the load listener pattern is not specific to Web Components, but something that’s worth doing in most projects.

A fair amount is going on in the initUI function, so let’s look at what’s going on step by step:

src/index.js
function initUI() {
  const firstNameField = document.querySelector('#firstName');
  const lastNameField = document.querySelector('#lastName');
  const addButton = document.querySelector('#addButton');
  const grid = document.querySelector('#grid'); (1)

  let people = []; (2)

  addButton.addEventListener('click', e => { (3)
    people = [ (4)
      ...people,
      {
        firstName: firstNameField.value,
        lastName: lastNameField.value
      }
    ];
    grid.items = people; (5)
    firstNameField.value = ''; (6)
    lastNameField.value = '';
  });
}
  1. Get references to the components with document.querySelector

  2. Define an array to hold the people that are added.

  3. Add a click listener on the button for adding people.

  4. Create a new array with all previous people and a newly created person. The name values can be retrieved from the value property on the components.

  5. Set the new people array as the items property on the grid to display the updated data.

  6. Clear the input fields.

Run the application, and you should now be able to add new entries to the grid.

Summary and next steps

Web Components behave like any other HTML element once you have imported them. You can set and read attributes and properties for data, and listen to events to add interactivity.

Web Components are designed to be framework independent. You can use them together with a framework or templating library to cut down on the boilerplate of manually querying elements and setting their values. See any of our other guides on using Web Components in popular frameworks for further information.

Source code on Github.

Vaadin is an open-source framework offering the fastest way to build web apps on Java backends
GET STARTED

Comments (14)

Marcus Hellberg
5 months ago May 10, 2021 7:20pm
Marcus Hellberg
2 years ago Aug 17, 2019 3:43am
David Chisholm
2 years ago Feb 24, 2020 4:14pm
Marcus Hellberg
2 years ago Dec 02, 2019 4:35pm
New User
3 years ago Apr 03, 2019 9:12pm
Marcus Hellberg
3 years ago Mar 02, 2019 5:00pm
Dmitriy Balakin
3 years ago Mar 02, 2019 6:05pm
Marcus Hellberg
3 years ago Mar 02, 2019 7:22pm