Skip to main contentCarbon Design System

1. Installing Carbon

Starting with Create React App, let’s install Carbon and begin using Carbon components. By the end you will have a React app that uses the UI Shell to navigate between pages.

Preview

A preview of what you will build:

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.

Fork

To begin, fork carbon-tutorial using your GitHub account.

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

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

git remote add upstream git@github.com:carbon-design-system/carbon-tutorial.git

HTTPS

git remote add upstream https://github.com/carbon-design-system/carbon-tutorial.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.git (fetch)
upstream git@github.com:carbon-design-system/carbon-tutorial.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 upstream
git checkout -b v11-react-step-1 upstream/v11-react-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 React app’s dependencies with:

yarn

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

yarn start

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 tutorial.

Install Carbon

Even though we installed existing dependencies, we’ve yet to install our v11 Carbon package, @carbon/react, which contains everything you need to build with.

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

yarn add @carbon/react@1.1.0

Install and build 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.

yarn add sass@1.51.0

To avoid having to add the ~ prefix when importing SCSS files from node_modules, create a .env file at the project root that contains:

.env
SASS_PATH="node_modules"

For the Windows operating system, use:

.env
SASS_PATH=./node_modules

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

yarn start

The app looks as it did before. Next, let’s prepare our app for a Sass build.

In the src directory, rename index.css as index.scss. Then in index.js update the index.css import to index.scss.

Import carbon-component styles

In index.scss, import the Carbon styles by adding the following at the top of the file:

src/index.scss
@use '@carbon/react';

Making this change to index.scss will cause all of the Carbon Sass to re-compile. Once finished re-compiling the Carbon base styling is applied (IBM Plex Sans font family, font size, weight, colors, etc.)

Re-compiling all of the Carbon Sass takes a while, even on fast systems. Let’s speed this up by moving our custom app Sass into a separate file, app.scss in the ‘src’ directory, and import that from App.js.

src/App.js
import './app.scss';

By modifying index.scss as little as possible and storing all app-specific styling in app.scss we will make compile times much quicker. Storing the app-specific styling in a separate file also makes good organizational sense.

Next, we’ll import a Button from Carbon to test that our dependencies are working properly. At the top of App.js, import the Button by adding the following:

src/App.js
import { Button } from '@carbon/react';

In the App component return, you can now replace:

src/App.js
<div>
Hello Carbon! Well, not quite yet. This is the starting point for the Carbon
tutorial.
</div>

with:

src/App.js
<Button>Button</Button>

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

Add UI Shell

Next, we’re going to create a React component called TutorialHeader to use with the UI Shell Carbon component. In the src directory, create a components directory and inside of that, a TutorialHeader directory. Create the following files inside src/components/TutorialHeader:

src/components/TutorialHeader
├──_tutorial-header.scss
├──index.js
└──TutorialHeader.js

Add UI Shell Sass

Next, in app.scss, we’ll import our TutorialHeader styles. Your file should now look like this:

src/app.scss
@use './components/TutorialHeader/tutorial-header';

Import and export the header

In src/components/TutorialHeader/index.js, import and export our TutorialHeader component like so:

src/components/TutorialHeader/index.js
import TutorialHeader from './TutorialHeader';
export default TutorialHeader;

Next we’ll import our Carbon UI Shell components into TutorialHeader.js. Set up the file like so:

src/components/TutorialHeader/TutorialHeader.js
import React from 'react';
import {
Header,
HeaderContainer,
HeaderName,
HeaderNavigation,
HeaderMenuButton,
HeaderMenuItem,
HeaderGlobalBar,

Note: you can find a description of the different components used UI Shell in our @carbon/react package.

Note: 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 icons

Now let’s import the icons. In the TutorialHeader.js file, we need to import each individual icon we will use.

src/components/TutorialHeader/TutorialHeader.js
import { Switcher, Notification, UserAvatar } from '@carbon/react/icons';

Then we need to add the HeaderGlobalAction component inside of the HeaderGlobalBar where we will add our icons. These represent actions in the header a user can make. Replace:

src/components/TutorialHeader/TutorialHeader.js
<HeaderGlobalBar />

With:

src/components/TutorialHeader/TutorialHeader.js
<HeaderGlobalBar>
<HeaderGlobalAction aria-label="Notifications" tooltipAlignment="center">
<Notification size={20} />
</HeaderGlobalAction>
<HeaderGlobalAction aria-label="User Avatar" tooltipAlignment="center">
<UserAvatar size={20} />
</HeaderGlobalAction>
<HeaderGlobalAction aria-label="App Switcher" tooltipAlignment="end">
<Switcher size={20} />

Render the header

Next we’ll render our UI Shell by importing our TutorialHeader component and Content into App.js. Your imports should look like this:

src/App.js
import React, { Component } from 'react';
import './app.scss';
import { Button, Content } from '@carbon/react';
import TutorialHeader from './components/TutorialHeader';

Our return currently just contains a Button. Let’s update that to include our imported components. This should look like the following:

src/App.js
class App extends Component {
render() {
return (
<>
<TutorialHeader />
<Content>
<Button>Button</Button>
</Content>
</>

You should now see a styled UI Shell header and a button below it.

Create pages

Next thing we need to do is create the files for our content. Start by creating a folder called content in src. This should be a sibling of src/components.

Since our app will have two pages, we’ll create two folders in src/content.

src/content
├── LandingPage
└── RepoPage

Next, we’ll set up these folders the same way we set up src/components/TutorialHeader.

Create the following files in the LandingPage folder:

src/content/LandingPage
├── _landing-page.scss
├── index.js
└── LandingPage.js

Create the following files in the RepoPage folder:

src/content/RepoPage
├── _repo-page.scss
├── index.js
└── RepoPage.js

Set up content Sass

Next, we’ll import our content Sass files in app.scss, like so:

src/app.scss
@use './components/TutorialHeader/tutorial-header';
@use './content/LandingPage/landing-page';
@use './content/RepoPage/repo-page';

Import and export content pages

Now that our stylesheets are set up, we need to create our pages’ components. Starting with LandingPage, just like with our header, we need to export the component in src/content/LandingPage/index.js by adding:

src/content/LandingPage/index.js
import LandingPage from './LandingPage';
export default LandingPage;

Next in LandingPage.js, we’ll create our component.

src/content/LandingPage/LandingPage.js
import React from 'react';
const LandingPage = () => {
return <div>LANDING PAGE</div>;
};
export default LandingPage;

We’ll repeat this process with RepoPage.

In src/content/RepoPage/index.js, import and export the RepoPage component like so:

src/content/RepoPage/index.js
import RepoPage from './RepoPage';
export default RepoPage;

Then in RepoPage.js create the component.

src/content/RepoPage/RepoPage.js
import React from 'react';
const RepoPage = () => {
return <div>REPO PAGE</div>;
};
export default RepoPage;

Awesome! We’ve just created our content pages. Next thing we need to do is render them with our router.

Add routing

We’ve updated our app to render our header, but now we need to add routing functionality. To do this we need to install react-router-dom. Go ahead and stop your development server (with CTRL-C) and then:

yarn add react-router-dom@5.0.0
yarn start

First, we need to wrap our app in the Router component. In the root index.js, add the import:

src/index.js
import { HashRouter as Router } from 'react-router-dom';

Note: We’re using HashRouter instead of BrowserRouter to simplify deployments in upcoming tutorial steps. Learn more about the React Router here.

Then, update the render() function to include the Router.

src/index.js
ReactDOM.render(
<Router>
<App />
</Router>,
document.getElementById('root')
);

In order to render our content pages, we need to add the following imports in App.js below our existing imports.

src/App.js
import { Route, Switch } from 'react-router-dom';
import LandingPage from './content/LandingPage';
import RepoPage from './content/RepoPage';

This allows us to use our page content components and routing components from react-router-dom.

The next thing we need to do is update what we’re returning to App.js. We currently just have a button in our content. In order to render our pages correctly, we need to delete the Button component within Content (and remove the Button import).

Now inside Content we’ll add the following:

src/App.js
<Switch>
<Route exact path="/" component={LandingPage} />
<Route path="/repos" component={RepoPage} />
</Switch>

After that we need to do a couple quick fixes to the UI Shell to have it work with the React router.

Add the Link import in TutorialHeader.js:

src/components/TutorialHeader/TutorialHeader.js
import { Link } from 'react-router-dom';

We need to use the Link component instead of the default anchor elements to prevent full page reload when navigating to different pages with React Router. To use Link, update the HeaderName component to use the element prop and replace the href with to:

src/components/TutorialHeader/TutorialHeader.js
<HeaderName element={Link} to="/" prefix="IBM">
Carbon Tutorial
</HeaderName>

Do the same with the components that contain href="/repos", updating them to:

src/components/TutorialHeader/TutorialHeader.js
<HeaderMenuItem element={Link} to="/repos">
Repositories
</HeaderMenuItem>

You should now have a working header that routes to different pages without full page reload! However, our page does not match the design specs. We need to change the header theme to g100 to match the specs.

In App.js we will add inline theming for our navigation. First, we need to import our new Theme component.

src/App.js
import { Content, Theme } from '@carbon/react';

Then, we will wrap Theme around our header, and set the zoned theme using the theme prop, which accepts one of four strings: "white", "g10", "g90" or "g100".

src/App.js
<>
<Theme theme="g100">
<TutorialHeader />
</Theme>
<Content>
<Switch>
<Route exact path="/" component={LandingPage} />
<Route path="/repos" component={RepoPage} />
</Switch>

You might have noticed that the landing and repo page content disappeared. This is because we now have a wrapper around the UI Shell, and the spacing is off. To fix this, we’ll add the following override in index.scss below our style import:

src/index.scss
.cds--content {
margin-top: 3rem;
}

We have one last thing to fix before we’re done. Because we changed the header theme to dark, the <HeaderGlobalAction> tooltips are now light instead of dark, and when you scroll the page, it blends into the content. To fix this, we’ll add some overriding styles in _tutorial-header.scss:

src/components/TutorialHeader/_tutorial-header.scss
@use '@carbon/react/scss/colors';
// overriding header tooltip bg color
// because the navigation is dark themed while the content is white
// which means the dark theme tooltip bg blends into the white content bg
.cds--header__global .cds--popover-content {
background-color: colors.$gray-20;
}

Submit pull request

We’re going to submit a pull request to verify completion of this tutorial step and demonstrate a couple of related concepts.

Continuous integration (CI) check

We have a ci-check script defined in package.json that verifies file formatting for files that have been touched since the last Git commit with a tool called Prettier. You’d typically also have that script run your test suite as part of your CI build. Go ahead and make sure everything looks good with:

yarn ci-check

Note: If the ci-check is giving an error, it’s likely that some of your source files are not properly formatted. This could happen if your text editor isn’t formatting with Prettier on save. To get ci-check to pass, run yarn format then re-run yarn ci-check.

Git commit and push

Before we can create a pull request, stage and commit all of your changes:

git add --all && git commit -m "feat(tutorial): complete step 1"

Note: You’ll notice that your commit includes binaries in the .yarn/cache folder. That’s expected as the repository is configured to run Yarn offline for more reliable builds. Future tutorial steps that don’t install new packages won’t have .yarn/cache commit changes.

Then, push to your repository:

git push origin v11-react-step-1

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.

Note: If you receive a non-fast-forward error, it’s likely that your forked repository is behind the original repository and needs to be updated. This can happen if the tutorial was updated after you began working on it. To fix, run git pull upstream v11-react-step-1 to merge the changes into your branch, then you can try pushing again. Or, you can manually merge in the upstream changes.

Pull request (PR)

Finally, visit carbon-tutorial to “Compare & pull request”. In doing so, make sure that you are comparing to v11-react-step-1 into base: v11-react-step-1. Take notice of the Netlify bot that deploys a preview of your PR every time that you push new commits. These previews can be shared and viewed by anybody to assist the PR review process.

Note: Expect your tutorial step PRs to be reviewed by the Carbon team but not merged. We’ll close your PR so we can keep the repository’s remote branches pristine and ready for the next person!

Note: If your PR fails the CircleCI test with the error Can't make a request in offline mode, try running the following command: rm -rf .yarn-offline-mirror node_modules && yarn cache clean && yarn install. Add and commit the changes once this completes, and try pushing again.