Web components tutorial

Last updated Jun 30, 2026

Learn more about building a Vanilla JavaScript and HTML application using Web Components from Carbon. This tutorial shows you how to use Carbon components effectively while introducing web development best practices along the way.

Web components tutorial

Overview

Starting from a base create-vite app, created using the Vanilla and Javascript options, let’s install Carbon and begin using Carbon components. By the end you will have a Vanilla app that uses the UI Shell to navigate between pages.

Fork, clone and branch

This tutorial has an accompanying GitHub repository called carbon-tutorial-web-components that we’ll use as a starting point for each step.

Fork

To begin, fork carbon-tutorial-web-components using your GitHub account. Please note when forking you must uncheck “Copy the main branch only” so you can access all branches / steps of the tutorial.

Clone

Go to your forked repository, copy the SSH or HTTPS URL and in your terminal run the two commands to get the repository in your local file system and enter that directory.

Add upstream remote

Add a remote called upstream so we can eventually submit a pull request once you have completed this tutorial step. There are two choices: SSH or HTTPS

SSH

HTTPS

Verify that your forked repository remotes are correct:

Your terminal should output something like this:

Branch

Now that we have our repository set up, let’s check out the branch for this tutorial step’s starting point. Run the two commands:

Build and start

We have the repository forked to your GitHub account, cloned down to your machine, and the starting branch checked out. Next, install the app’s dependencies (Vite) with:

After the dependencies are installed, you can start the app with:

Open Your default browser should open up with an empty page that says: Hello Carbon! Well, not quite yet. This is the starting point for the Carbon Web Components tutorial.

Install Carbon

Even though we installed existing dependencies, we’ve yet to install our any Carbon packages.

Stop your development server with CTRL-C and install Carbon dependencies with:

Install Sass

We need to run a Sass build as the Carbon styles are authored in Sass, so run the following command to install sass as a dependency.

Before restarting our app rename style.css to style.scss and change the import in main.js from import './style.css'; to import './style.scss';.

Then, start the app again. If your app’s currently running, you’ll need to restart it for the new packages to be used.

The app looks as it did before. We, need to import Carbon styles have an impact.

Import Carbon styles

Replace the contents of style.scss with

This has reset the styles to a common base from which Carbon applications are built. What you see, if you run the application, is a largely unstyled page. It is however making use of the IBM Plex font, standard in all Carbon applications.

A working Carbon button

Import the button

Next, we’ll import a Button from Carbon to test that our dependencies are working properly. At the top of main.js, import the Button and delete everything else, leaving just:

Tidy up our HTML file

In index.html first move this script tag up inside the head tag, so we don’t accidentally delete it later. It’s location does not matter in this tutorial.

Then replace the Vite logo

with the Carbon one:

Update the title Vite App to Carbon tutorial web components.

Add the button by replacing:

with:

Congratulations, you’ve imported your first component! You should see a Carbon styled button on the page.

Make the button do something

Before giving the button something to do, add the following to style.scss which will allow our button to theme the app.

Then in main.js add the following code to handle the button clicks.

After these changes clicking the button will toggle theme classes, which in the app changes the background color.

Add UI Shell

Now we’re going to add the UI shell.

UI Shell for the landing page

First import the header into main.js

Note: you can find a description of the different components used in the UI Shell in our Storybook package.

Before we add the header to index.html add the class app to the body tag.

Wrap the button as follows.

Then above <main> add our header.

Running the application at this point it looks like the button has disappeared. Add the following to style.scss.

This imports the Carbon spacing and establishes a grid to contain our header and main. The overflow settings are there to ensure it is our <main> that scrolls if needed.

Adding the repositories page

After the <cds-header-name> closing tag add a link to a new page.

Duplicate index.html and name it repositories.html.

In this new file replace the contents of the main tag with the words REPOSITORIES PAGE.

You can now switch between the two pages by clicking on Repositories and IBM Carbon Tutorial in the header. This will look a little glitchy, this is because it is a genuine page navigation, and the CSS is still being processed. When using Web Components inside libraries such as Lit, React, Angular, Vue etc this is resolved by taking control of the routing. We will not investigate further here.

Behaving responsively

Switch back to the landing page by clicking on IBM Carbon Tutorial.

Checking responsive behavior (window narrower than 1080px) you will notice the repositories page disappear from the menu. This goes into a sidebar controlled by a hamburger menu as follows.

Before the <cds-header-name> tag add

Then after the closing </cds-header-nav> add

Global actions

As part of the Carbon header we can also add global actions this involves making use of some Carbon Icons so first we will add that dependency.

There are various ways to add SVGs to our page. Often the SVG is copied directly into source HTML or a bundler is used to load it. Rather than rely on a bundler or add them inline, which can make our HTML harder to read, we will use CSS to add refer directly to the icon files (which have been conveniently copied into the ./public folder) from the @carbon/icons package.

The above CSS allows us to simply add the two classes associated with each icon to display it in a themeable way in our application.

Next we need to add the global actions and related panels to the index.html file after the closing </cds-side-nav>. The Carbon icons are applied to the slotted icon element using CSS.

Note: this is the first time we have seen the slot attribute. Standard HTML elements often have the ability to host child content. Web components are more flexible allowing both the default child and named child areas, it uses the term slot to refer to these. The slot attribute is used to target named slots, in this case icon.

Further details on slots can be found on the mdn docs package.

The global action buttons are passed a panel-id used to identify the panels they toggle the visibility of. Just below the last global action add the following HTML.

Note as web components behave like native components we can add event handlers and interact with them directly.

The default panel behavior simply toggles the panel when clicked. This can result in multiple panels being open at once. Adding the following to main.js changes this behavior by listening for clicks and closing the other panels.

A better theme switcher

The current theme switcher is not very practical, here we will move it inside the profile panel.

First replace the button in index.html with LANDING PAGE leaving the main tag looking like this.

In main.js remove this code handling the button click and initial load.

Still in main.js add imports for checkbox and content-switcher.

Locate the cds-header-panel with the id=“user-profile-panel” in index.html and replace it’s content with the following.

This adds a content switcher and checkbox to our user profile side panel. If you view it now it works but is in need of some styling.

These styles import the Carbon typography features, define a layout for our panel, and set the title size.

As per the global actions we will use additional styling to add icons to our content switcher.

Currently the theme switcher looks good but needs the following Javascript to switch themes.

At this point our theme switcher is mostly working, only the checkbox Global header reverse theme appears to do nothing. In the script above the class compliment is being toggled on and off in the <header> tag.

A little more CSS is needed to make this functionality work. Add the following in addition to the existing theme classes.

Then replace the cds-header tags g100 class in index.html with compliment.

Skip to content

When creating navigation headers, it’s important to have a Skip to content link so keyboard users can skip the navigation items and go straight to the main content.

Import the component in main.js

Add in to our header in index.html as the first child of our cds-header component.

Then update the main tag to include the id main-content

Update the repositories page

One final task before completing step 1. Our repositories page has missed out on all of the HTML updates we have been making to the landing page. Simply copy the contents of index.html to repositories.html and replace LANDING with REPOSITORIES.

NOTE: We could do something better than duplicating our pages. This could be pure Javascript, HTML templates or native Web Components. However, that might distract from the message that no library is required.

Push to GitHub

That is it you are done. Just one more push to save your completion of step 1.

Git commit and push

First, stage and commit all of your changes:

Then, push to your repository:

Note: If your Git remote protocol is HTTPS instead of SSH, you may be prompted to authenticate with GitHub when you push changes. If your GitHub account has two-factor authentication enabled, we recommend that you follow these instructions to create a personal access token for the command line. That lets you use your token instead of password when performing Git operations over HTTPS.