1. Installing Carbon
Starting from a base
create-vite
Vanilla
Javascript
- Fork, clone and branch
- Build and start
- Install Carbon
- Install Sass
- A working Carbon button
- Add UI Shell
- Push to GitHub
Preview
A preview of what you will build:
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 untick “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.
git clone [your fork SSH/HTTPS]cd carbon-tutorial-web-components
Add upstream remote
Add a remote called
upstream
SSH
git remote add upstream git@github.com:carbon-design-system/carbon-tutorial-web-components.git
HTTPS
git remote add upstream https://github.com/carbon-design-system/carbon-tutorial-web-components.git
Verify that your forked repository remotes are correct:
git remote -v
Your terminal should output something like this:
origin [your forked repo] (fetch)origin [your forked repo] (push)upstream git@github.com:carbon-design-system/carbon-tutorial-web-components.git (fetch)upstream git@github.com:carbon-design-system/carbon-tutorial-web-components.git (push)
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:
git fetch upstreamgit checkout -b step-1 upstream/step-1
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:
pnpm i
After the dependencies are installed, you can start the app with:
pnpm dev
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
pnpm add @carbon/web-components @carbon/styles
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
pnpm add sass
Before restarting our app rename
style.css
style.scss
main.js
import './style.css';
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.
pnpm dev
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
@use '@carbon/styles/scss/reset';
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
main.js
Button
import './style.scss';import '@carbon/web-components/es/components/button/button.js';
Tidy up our HTML file
In
index.html
head
<script type="module" src="/main.js"></script>
Then replace the Vite logo
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
with the Carbon one:
<link rel="icon" type="image/svg+xml" href="/carbon.svg" />
Update the title
Vite App
Carbon tutorial web components
Add the button by replacing:
<div id="app"></div>
with:
<cds-button class="button">Click more than once</cds-button>
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
@use '@carbon/styles/scss/theme' as *;@use '@carbon/styles/scss/themes';:root {@include theme(themes.$g10);@media (prefers-color-scheme: dark) {@include theme(themes.$g100);}
Then in
main.js
const bodyEl = document.querySelector('body');// button click handlerconst handleClick = () => {bodyEl.classList.toggle('g10');bodyEl.classList.toggle('g100');};document.querySelector('.button').addEventListener('click', handleClick);
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
import '@carbon/web-components/es/components/ui-shell/index';
Before we add the header to
index.html
app
<body class="app"></body>
Wrap the button as follows.
<main class="main"><cds-button class="button">Click more than once</cds-button></main>
Then above
<main>
<header><cds-header class="g100"><cds-header-name href="./" prefix="IBM">Carbon Tutorial</cds-header-name></cds-header></header>
Running the application at this point it looks like the button has dissapeared. Add the following to
style.scss
@use '@carbon/styles/scss/spacing' as *; /* near top of file */.app {display: grid;grid-template-rows: $spacing-09 1fr;height: 100vh;overflow: hidden;}
This imports the Carbon
spacing
<main>
Adding the repositories page
After the
<cds-header-name>
<cds-header-nav menu-bar-label="Carbon Tutorial"><cds-header-nav-item href="./repositories.html">Repositories</cds-header-nav-item></cds-header-nav>
Duplicate
index.html
repositories.html
In this new file replace the contents of the
main
REPOSITORIES PAGE
You can now switch between the two pages by clicking on
Repositories
IBM Carbon Tutorial
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>
<cds-header-menu-buttonbutton-label-active="Close menu"button-label-inactive="Open menu"></cds-header-menu-button>
Then after the closing
</cds-header-nav>
<cds-side-navis-not-persistentaria-label="Side navigation"collapse-mode="${SIDE_NAV_COLLAPSE_MODE.RESPONSIVE}"><cds-side-nav-items><cds-side-nav-link href="./repositories.html">Repositories</cds-side-nav-link></cds-side-nav-items>
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.
pnpm add @carbon/icons
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
@carbon/icons
.action-icon {width: 1.25rem;height: 1.25rem;background-color: $text-primary;}.notification .action-icon {mask: url('/notification.svg') no-repeat center;}
The above CSS allows us to simply add the two classes associated with each icon to display it in a themable way in our application.
Next we need to add the global actions and related panels to the
index.html
</cds-side-nav>
<div class="cds--header__global"><cds-header-global-actionaria-label="Notifications"class="notification"panel-id="notification-panel"><div class="action-icon" slot="icon"></div></cds-header-global-action><cds-header-global-actionaria-label="User Profile"
The global action buttons are passed a
panel-id
<cds-header-panel id="notification-panel" aria-label="Notification Panel">Notification Panel</cds-header-panel><cds-header-panel id="user-profile-panel" aria-label="User profile Panel">User profile Panel</cds-header-panel><cds-header-panel id="app-switcher-panel" aria-label="App switcher Panel">App switcher Panel</cds-header-panel>
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
const handleGlobalActionClick = (ev) => {const targetPanelId = ev.currentTarget.getAttribute('panel-id');const panels = document.querySelectorAll('cds-header-panel');// check to see if other panels are open and close thempanels.forEach((panel) => {if (panel.id !== targetPanelId) {panel.expanded = false;}});
A better them 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
LANDING PAGE
<main class="main">LANDING PAGE</main>
In
main.js
// button click handlerconst handleClick = () => {bodyEl.classList.toggle('g10');bodyEl.classList.toggle('g100');};document.querySelector('.button').addEventListener('click', handleClick);// set initial theme based on preferencesif (matchMedia('(prefers-color-scheme: dark)')) {
Still in
main.js
import '@carbon/web-components/es/components/checkbox/index';import '@carbon/web-components/es/components/content-switcher/index';
Locate the
cds-header-panel
index.html
<div class="header-panel__content"><h2 class="header-panel__title">User profile Panel</h2><cds-content-switcher value="system" class="theme-selector"><cds-content-switcher-item icon value="light"><div class="theme-selector__icon theme-selector__icon--light"></div><span slot="tooltip-content">Light theme</span></cds-content-switcher-item><cds-content-switcher-item icon value="system">
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.
@use '@carbon/styles/scss/type' as *; /* place at top of file */.header-panel__content {display: flex;flex-direction: column;gap: $spacing-05;padding: $spacing-05;}
As per the global actions we will use additional styling to add icons to our content switcher.
.theme-selector__icon {width: 1.25rem;height: 1.25rem;background-color: $text-primary;}cds-content-switcher-item[selected] .theme-selector__icon {/* switch icon color when selected */background-color: $background;
Currently the theme switcher looks good but needs the following Javascript to switch themes.
const handleSwitch = (ev) => {// Applies new theme or defers to system preferences by removing themeswitch (ev.detail.item.value) {case 'light':bodyEl.classList.remove('g100');bodyEl.classList.add('g10');break;case 'dark':bodyEl.classList.remove('g10');
At this point our theme switcher is mostly working, only the checkbox
Global header reverse theme
compliment
<header>
A little more CSS is needed to make this functionality work. Add the following in addition to the existing theme classes.
:root .compliment {@include theme(themes.$g100);@media (prefers-color-scheme: dark) {@include theme(themes.$g10);}}.g10 .compliment {
Then replace the cds-header tags
g100
index.html
compliment
<cds-header class="compliment"> . . . </cds-header>
Skip to content
When creating navigation headers, it’s important to have a
Skip to content
Import th ecomponent in
main.js
import '@carbon/web-components/es/components/skip-to-content/index.js';
Add in to our header in
index.html
cds-header
<cds-header class="compliment"><cds-skip-to-content href="#main-content"></cds-skip-to-content><!-- keep existing content...--></cds-header>
Then update the main tag to include the id
main-content
<main id="main-content" class="main"><!-- keep existing content...--></main>
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
repositories.html
LANDING
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:
git add --all && git commit -m "feat(tutorial): complete step 1"
Then, push to your repository:
git push -u origin step-1