Skip to main contentCarbon Design System

2. Building pages

Now that we have a base Angular app, it’s time to build a few static pages. In this step, we’ll become comfortable with the Carbon UI Shell, grid and various Carbon components.

Preview

A preview of what you’ll build:

Fork, clone and branch

This tutorial has an accompanying GitHub repository called carbon-tutorial-angular 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.

Branch

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 angular-step-2 upstream/angular-step-2

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):

npm install

Then, start the app:

npm start

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

Add grid

In our last step we added our styles, components and icon packages. Now we are going to build the pages with the grid component.

In styles.scss, we need to configure our grid to use 16 columns instead of the default 12 columns. We do this by adding grid-columns-16: true in our $feature-flags. $feature-flags must be set before importing from carbon-components, otherwise they won’t take affect.

src/styles.scss
$feature-flags: (
grid-columns-16: true
);

Next we’ll import our Carbon grid component into home.module.ts and landing-page.component.spec.ts.

src/app/home/landing-page/landing-page.component.spec.ts,src/app/home/home.module.ts
import { GridModule } from 'carbon-components-angular';
...
@NgModule({
...
imports: [GridModule]
})

Add landing page grid

Let’s add our grid elements to landing-page.component.html.

In order to use the grid, we need to wrap everything in a <div ibmGrid>. We can continue to make rows by adding a <div ibmRow> inside the grid, as well as make columns within those rows by adding <div ibmCol [columnNumbers]="{'[breakpoint]': [size]}".

Our column sizes are specified by the number of columns they’ll be spanning. If we use [columnNumbers]="{'lg': 4}", it means it’ll span 4 of the 16 columns. If we use [columnNumbers]="{'lg': 8}" it means it’ll span 8 of the 16 columns, and so on.

We’ve included the designs for this tutorial app in the design.sketch file found as a top-level file in the carbon-tutorial-angular repository. But, if you don’t have Sketch installed and available to inspect the design, we provide screenshots.

Landing page grid

Landing page grid

We’ll break this down into three rows. The first row with the gray background doesn’t appear to need any columns. The second row with the white background looks like it has two columns of different widths. The third row with the gray background looks like it has four columns of equal width.

We’ll make rows like so:

src/app/home/landing-page/landing-page.component.html
<div ibmGrid class="bx--grid--full-width landing-page">
<div ibmRow class="landing-page__banner">
<div ibmCol [columnNumbers]="{'lg': 16}">1</div>
</div>
<div ibmRow class="landing-page__r2">
<div ibmCol [columnNumbers]="{'md': 4, 'lg': 7}">7/16</div>
<div ibmCol class="bx--offset-lg-1" [columnNumbers]="{'md': 4, 'lg': 7}">
8/16
</div>

We added a class of bx--grid--full-width to the grid container since our rows need to expand the whole page without any margins. We also added some custom classes like landing-page, landing-page__banner, landing-page__r2, etc., which we will use later.

Also, take notice of the second row. The tab content only covers 7 columns at this large viewport to prevent overly-large line lengths, so we needed to add a 1 column offset bx--offset-lg-1 to the second column to fill the full 16 columns in the grid. Then, both of those columns have 'md': 4 so they are of equal width at medium-sized viewports.

Build landing page

We’ll start adding HTML elements and components by row.

First row

In our first row we’ll need a Breadcrumb component. First, let’s import the components we need in home.module.ts and landing-page.component.spec.ts.

src/app/home/home.module.ts,src/app/home/landing-page/landing-page.component.spec.ts
import { BreadcrumbModule, GridModule } from 'carbon-components-angular';
src/app/home/home.module.ts,src/app/home/landing-page/landing-page.component.spec.ts
imports: [BreadcrumbModule, GridModule];

We can now add our component to the first row, along with a header, like so:

src/app/home/landing-page/landing-page.component.html
<div ibmRow class="landing-page__banner">
<div ibmCol [columnNumbers]="{'lg': 16}">
<ibm-breadcrumb noTrailingSlash="true">
<ibm-breadcrumb-item href="/"> Getting started </ibm-breadcrumb-item>
</ibm-breadcrumb>
<h1 class="landing-page__heading">Design &amp; build with Carbon</h1>
</div>
</div>

You may notice that the styles look off. Don’t worry, we’ll fix these later.

Second row

In our second row we’ll need Tabs and Button components also in home.module.ts and landing-page.component.spec.ts. We’ll update the carbon-components-angular import to:

src/app/home/home.module.ts,src/app/home/landing-page/landing-page.component.spec.ts
import {
BreadcrumbModule,
ButtonModule,
GridModule,
TabsModule,
} from 'carbon-components-angular';
src/app/home/home.module.ts,src/app/home/landing-page/landing-page.component.spec.ts
imports: [BreadcrumbModule, ButtonModule, GridModule, TabsModule];

Now we need to modify the second row to use the Tab component.

src/app/home/landing-page/landing-page.component.html
<div ibmRow class="landing-page__r2">
<div ibmCol class="bx--no-gutter">
<ibm-tabs>
<ibm-tab heading="About">
<div ibmGrid class="bx--grid--no-gutter bx--grid--full-width">
<div ibmRow class="landing-page__tab-content">
<div ibmCol [columnNumbers]="{'md': 4, 'lg': 7}">7/16</div>
<div
ibmCol

Hold up! If you were to run DAP to check for accessibility violations, you’d see Multiple navigation landmarks must have unique labels specified with aria-label or aria-labelledby because both the Breadcrumb and Tabs components use <nav> elements. To fix, add ariaLabel to the Breadcrumb opening tag:

src/app/home/landing-page/landing-page.component.html
<ibm-breadcrumb noTrailingSlash="true" ariaLabel="Page navigation">

Same goes for the Tabs opening tag:

<ibm-tabs ariaLabel="Tab navigation">

Next, we’ll need to add a styling override to move the tabs to the right on large viewports, and tidy up the alignment of the grid. Create a file carbon-overrides.scss in src/assets/scss with this declaration block.

src/assets/scss/carbon-overrides.scss
// makes the grid fit the entire width of the page
.bx--grid--full-width {
padding-left: 1rem;
padding-right: 1rem;
}
// removes excess padding for nested full width grids
.bx--grid--full-width .bx--grid--full-width {
padding-left: 0;

Then in styles.scss add this import after the Carbon styles.scss import.

src/styles.scss
@import './assets/scss/carbon-overrides.scss';

We can now add our images and text for each column in the first Tab in landing-page.component.html.

src/app/home/landing-page/landing-page.component.html
<ibm-tab heading="About">
<div ibmGrid class="bx--grid--no-gutter bx--grid--full-width">
<div ibmRow class="landing-page__tab-content">
<div ibmCol [columnNumbers]="{'md': 4, 'lg': 7}">
<h2 class="landing-page__subheading">
What is Carbon?
</h2>
<p class="landing-page__p">
Carbon is IBM’s open-source design system for digital

Now let’s download the image in src/assests and set the image size in landing-page.component.scss:

curl -o tab-illo.png https://raw.githubusercontent.com/carbon-design-system/carbon-tutorial-vue/vue-step-3/src/assets/tab-illo.png
src/app/home/landing-page/landing-page.component.scss
.landing-page__illo {
max-width: 100%;
}

Assuming that the second and third tab would have a similar design, we would set them up in the same way. However, since our design specs don’t show those tabs, we’ll leave the code as is.

Third row

The third row will be created in a later tutorial, so we’ll just add the headers for now.

src/app/home/landing-page/landing-page.component.html
<div ibmRow class="landing-page__r3">
<div ibmCol [columnNumbers]="{'md': 4, 'lg': 4}">
<h3 class="landing-page__label">The Principles</h3>
</div>
<div ibmCol [columnNumbers]="{'md': 4, 'lg': 4}">Carbon is Open</div>
<div ibmCol [columnNumbers]="{'md': 4, 'lg': 4}">Carbon is Modular</div>
<div ibmCol [columnNumbers]="{'md': 4, 'lg': 4}">Carbon is Consistent</div>
</div>

Style landing page

We’ve added basic layout styles in landing-page.component.scss and styles.scss, so now let’s add type, color and spacing styles to match the design. We’ll be using our spacing tokens. In landing-page.component.scss, add these imports at the top of the file so we can use Carbon breakpoints, tokens, and typography Sass mixins and functions:

src/app/home/landing-page/landing-page.component.scss
@import '~carbon-components/scss/globals/scss/vendor/@carbon/type/scss/font-family';
@import '~carbon-components/scss/globals/scss/typography';
Banner vertical spacing

Banner vertical spacing

Now, we need to add a space above the breadcrumb and below the heading. For that, add:

src/app/home/landing-page/landing-page.component.scss
.landing-page__banner {
padding-top: $spacing-05;
padding-bottom: $spacing-07 * 4;
}

Referencing the spacing token table, 16px can be set with the $spacing-05 token. The design calls for 128px of space below the heading and that’s not in the spacing scale, we can achieve that in Sass by multiplying 32px ($spacing-07) by 4. We could use 128px or 8rem directly in our styling, but using our tokens preserves consistency should the token values get updated in the future.

Looking at the design, we need a wall-to-wall light gray background behind the banner and also behind the third row. This is a great opportunity to use a Sass mixin. We will put this at the top of landing-page.component.scss.

Per the design we need to use Gray 10 for our banner background color, which can be set with the $ui-01 color token. Also, we want the background to extend into the grid’s outermost gutters to go the full width of the viewport, so given the DOM structure, we can achieve that by setting the background in an absolutely positioned pseudo element.

src/app/home/landing-page/landing-page.component.scss
@mixin landing-page-background() {
background-color: $ui-01;
position: relative;
&::before {
content: '';
position: absolute;
left: -$spacing-05;
top: 0;

Now to use the new mixin, update the .landing-page__banner declaration block to:

src/app/home/landing-page/landing-page.component.scss
.landing-page__banner {
padding-top: $spacing-05;
padding-bottom: $spacing-07 * 4;
@include landing-page-background;
}

Next, we can see that the h1 is using the heading-05 type token.

Banner heading type

Banner heading type

The Sketch symbol naming is consistent with the development Sass tokens to help translate design to development. So, looking up the type token, we know to use productive-heading-05:

src/app/home/landing-page/landing-page.component.scss
.landing-page__heading {
@include carbon--type-style('productive-heading-05');
}

Row two

For our second row, we need to fix the tabs vertical positioning to match the design. By inspecting the tabs component, you can see that the tab height computes to 40px. We can use that to create our negative top margin in rem units.

src/app/home/landing-page/landing-page.component.scss
.landing-page__r2 {
margin-top: rem(-40px);
}

We also need to adjust our vertical spacing and type treatment. Like before, it’s a matter of using spacing and type tokens like so:

Row 2 vertical spacing

Row 2 vertical spacing

src/app/home/landing-page/landing-page.component.scss
.landing-page__tab-content {
padding-top: $layout-05;
padding-bottom: $layout-05;
}
.landing-page__subheading {
@include carbon--type-style('productive-heading-03');
@include carbon--font-weight('semibold');
}

Row three

Row 3 vertical spacing

Row 3 vertical spacing

Let’s also add some styles for the last row, even though that will get used later in the tutorial. You’ll notice that we get to re-use the landing-page-background mixin that we just created.

src/app/home/landing-page/landing-page.component.scss
.landing-page__r3 {
padding-top: $spacing-09;
padding-bottom: $spacing-09;
@include landing-page-background;
}
.landing-page__label {
@include carbon--type-style('heading-01');
}

Ta-da! You should see a finished landing page! Now we can move on to the repo page.

Add repo page grid

First, we’ll add our grid and table by importing a few components in repositories.module.ts and repo-page.component.spec.ts:

src/app/repositories/repositories.module.ts,src/app/repositories/repo-page/repo-page.component.spec.ts
import { GridModule, TableModule } from 'carbon-components-angular';
src/app/repositories/repositories.module.ts,src/app/repositories/repo-page/repo-page.component.spec.ts
imports: [GridModule, TableModule];

Now in our repo-page.component.html we will add our grid containers.

src/app/repositories/repo-page/repo-page.component.html
<div ibmGrid class="bx--grid--full-width bx--grid--no-gutter repo-page">
<div ibmRow class="repo-page__r1">
<div ibmCol [columnNumbers]="{'lg': 16}">Data table will go here</div>
</div>
</div>

Build repo page

We currently have the repo-page that just contains a grid and placeholder content for the time being. In the next tutorial step we’re going to be querying an API to populate the Table component in this page. As a best practice to separate data fetching from the presentation components, go ahead and create a repo-table component as a sibling to repo-page.

ng g component repositories/repo-table --lint-fix
Folder structure
src/app/repositories
├── repo-table.component.html
├── repo-table.component.scss
├── repo-table.component.spec.ts
└── repo-table.component.ts

Next we will add our newly generated repo-table to the declarations in repo-page.component.spec.ts

src/app/repositories/repo-page/repo-page.component.spec.ts
import { RepoTableComponent } from '../repo-table/repo-table.component';
src/app/repositories/repo-page/repo-page.component.spec.ts
declarations: [ RepoPageComponent, RepoTableComponent ],

Build data table

Then, let’s create the table in repo-table.component.html

src/app/repositories/repo-table/repo-table.component.html
<ibm-table-container>
<ibm-table-header>
<h4 ibmTableHeaderTitle>Carbon Repositories</h4>
<p ibmTableHeaderDescription>A collection of public Carbon repositories.</p>
</ibm-table-header>
<ibm-table
[model]="model"
[showSelectionColumn]="false"
[striped]="false">

Instead of the usual write-your-own-html approach you had with <table>, Carbon table uses the model-view-controller approach.

Here, you create a view (with built-in controller) and provide it a model. Changes you make to the model are reflected in the view.

Render data table

Then include the following arrays to pass into the repo-table.component.ts component. We’ll be setting the rows array from an API in the next tutorial step, but for now, static example rows will suffice.

src/app/repositories/repo-table/repo-table.component.ts
import { Component, OnInit } from '@angular/core';
import {
TableModel,
TableItem,
TableHeaderItem,
} from 'carbon-components-angular';
@Component({

At this point, go to repo-page.component.html because now we need to render a static repo-table.

src/app/repositories/repo-page/repo-page.component.html
<div