Skip to main contentCarbon Design System

4. Creating components

With two pages comprised entirely of Carbon components, let’s revisit the landing page and build a couple components of our own by using Carbon icons and tokens.


Carbon provides a solid foundation for building web applications through its color palette, layout, spacing, type, as well as common building blocks in the form of components. So far, we’ve only used Carbon components to build out two pages.

Next, we’re going to use Carbon assets to build application-specific components. We’ll do so by including accessibility and responsive considerations all throughout.

A preview of what you’ll build (see bottom of page):

Fork, clone and branch

This tutorial has an accompanying GitHub repository called carbon-tutorial that we’ll use as a starting point for each step. If you haven’t forked and cloned that repository yet, and haven’t added the upstream remote, go ahead and do so by following the step 1 instructions.


With your repository all set up, let’s check out the branch for this tutorial step’s starting point.

git fetch upstream
git checkout -b vue-step-4 upstream/vue-step-4

Build and start app

Install the app’s dependencies (in case you’re starting fresh in your current directory and not continuing from the previous step):


Then, start the app:

yarn serve

You should see something similar to where the previous step left off.

Review design

Here’s what we’re building – an informational section that has a heading and three subheadings. Each subheading has accompanying copy and a pictogram. We’ll assume that this informational section is used elsewhere on the site, meaning it’s a great opportunity to build it as a reusable component. As for naming, we’ll call it an InfoSection with three InfoCards as children.

Info section layout

Info section layout

Create components

First we need files for the components, so create an InfoSection folder in src/components. Even though we’re building multiple components, their names all start with Info, so it makes sense to have them share one folder in components. Create these files:

Add files


Like our other components, index.js will serve as an entrypoint.

import InfoSection from './InfoSection';
import InfoCard from './InfoCard';
export { InfoSection, InfoCard };

InfoSection component

Let’s create the parent component that includes the “The Principles” heading. That markup currently looks like this in LandingPage.vue:

<div class="bx--row landing-page__r3">
<div class="bx--col-md-4 bx--col-lg-4">
<h3 class="landing-page__label">The Principles</h3>
<div class="bx--col-md-4 bx--col-lg-4">Carbon is Open</div>
<div class="bx--col-md-4 bx--col-lg-4">Carbon is Modular</div>
<div class="bx--col-md-4 bx--col-lg-4">Carbon is Consistent</div>

We want to do a few things when abstracting it to a component. First, we only want Carbon (bx--) and this component’s class names; we don’t want to include landing-page__r3 as that’s specific to the landing page. That will be passed in as a property to the component.

We’ll also:

  • Add component class names like info-section and info-section__heading
  • Semantically use <section> instead of <div>
  • Update the grid columns to match the design
  • Replace The Principles with {{heading}}
  • Replace columns 2 - 4 with a slot.

Using props we can render any heading and any number of children components (InfoCard that we’ll build soon.)

<section class="bx--row info-section">
<div class="bx--col-md-8 bx--col-lg-4 bx--col-xlg-3">
<h3 class="info-section__heading">{{ heading }}</h3>
<slot />

Then name our component and add a property to the script section.

export default {
name: "InfoSection",
props: {
heading: String

At this point let’s add styling for the new class names that we just added.

<style lang="scss">
@import "../../styles/_carbon-utils";
.info-section__heading {
@include carbon--type-style('heading-01');

InfoCard component

Next up we’re going to build a component for columns 2 - 4, which currently looks like <div class="bx--col-md-4 bx--col-lg-4">Carbon is Open</div>. Create a new file InfoCard.vue, add:

class="info-card bx--col-md-4 bx--col-lg-4 bx--col-xlg-3 bx--offset-xlg-1"
<h4 class="info-card__heading">{{ heading }}</h4>
<p class="info-card__body">{{ body }}</p>
<component :is="icon" />

Give it a name and add props

export default {
name: "InfoCard",
props: {
heading: String,
body: String,
icon: Object

In doing so, we:

  • Used the semantic <article> instead of <div>
  • Added info-card classes
  • Used props to render the heading, body copy, and icon
  • Set columns to match the grid

Use components

Our styling is not complete yet, but with our components built let’s put them to use. In LandingPage.vue, import the components towards the top of the script section. If you haven’t added a script section, do so now.

import { InfoSection, InfoCard } from '../../components/InfoSection';
export default {
name: 'LandingPage',
components: { InfoSection, InfoCard }</