{"componentChunkName":"component---src-pages-tutorial-angular-step-4-mdx","path":"/tutorial/angular/step-4/","result":{"pageContext":{"frontmatter":{"title":"4. Creating components","tabs":["Overview","Step 1","Step 2","Step 3","Step 4","Step 5","Wrapping up"]},"relativePagePath":"/tutorial/angular/step-4.mdx","titleType":"prepend","MdxNode":{"id":"00c6c96d-261c-5b78-8bcc-1ca57807c9f6","children":[],"parent":"853f14f6-457f-59e8-8f3d-4baaa7a0eafa","internal":{"content":"---\ntitle: 4. Creating components\ntabs:\n  ['Overview', 'Step 1', 'Step 2', 'Step 3', 'Step 4', 'Step 5', 'Wrapping up']\n---\n\nimport Preview from 'components/Preview';\n\n### 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.\n\n<AnchorLinks>\n\n<AnchorLink>Fork, clone and branch</AnchorLink>\n<AnchorLink>Review design</AnchorLink>\n<AnchorLink>Create components</AnchorLink>\n<AnchorLink>Use components</AnchorLink>\n<AnchorLink>Add styling</AnchorLink>\n<AnchorLink>Check accessibility</AnchorLink>\n<AnchorLink>Submit pull request</AnchorLink>\n\n</AnchorLinks>\n\n## Preview\n\nCarbon 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.\n\nNext, we're going to use Carbon assets to build application-specific components. We'll create our components with considerations for accessibility and responsiveness.\n\nA [preview](https://angular-step-5-carbon-tutorial.netlify.com) of what you'll build (see bottom of page):\n\n<Preview\n  height=\"400\"\n  title=\"Carbon Angular Tutorial Step 4\"\n  src=\"https://angular-step-5-carbon-tutorial.netlify.com\"\n  frameborder=\"no\"\n  allowtransparency=\"true\"\n  allowfullscreen=\"true\"\n/>\n\n<InlineNotification>\n\n**Note:** If you get lint errors when you copy the code from the snippets, run `ng lint --fix` to fix them.\n\n</InlineNotification>\n\n## Fork, clone and branch\n\nThis tutorial has an accompanying GitHub repository called [carbon-tutorial-angular](https://github.com/carbon-design-system/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](/tutorial/angular/step-1#fork-clone--branch).\n\n### Branch\n\nWith your repository all set up, let's check out the branch for this tutorial step's starting point.\n\n```bash\ngit fetch upstream\ngit checkout -b angular-step-4 upstream/angular-step-4\n```\n\n<InlineNotification>\n\n**Note:** This builds on top of step 3, but be sure to check out the upstream step 4 branch because it includes the static assets required to get through this step.\n\n</InlineNotification>\n\n### Build and start app\n\nInstall the app's dependencies (in case you're starting fresh in your current directory and not continuing from the previous step):\n\n```bash\nnpm install\n```\n\nThen, start the app:\n\n```bash\nnpm start\n```\n\nYou should see something similar to where the [previous step](/tutorial/angular/step-3) left off.\n\n## Review design\n\nHere'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 resusable component. As for naming, we'll call it an `InfoSection` with three `InfoCard`s as children.\n\n![Info section layout](../shared/step-4/images/info-layout.png)\n\n<Caption>Info section layout</Caption>\n\n## Create components\n\nFirst we need files for the components, so create an `Info` 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:\n\n### Generate modules & components using the Angular CLI\n\nLet's generate a new module that'll handle our `InfoCard` and `InfoSection` components:\n\n```bash\nng generate module info\n```\n\nNow we generate our `InfoCard` and `InfoSection` components:\n\n```bash\nng generate component info/info-card --lint-fix\n```\n\n```bash\nng generate component info/info-section --lint-fix\n```\n\n<InlineNotification>\n\n**Note:** The `--lint-fix` flag will automatically resolve lint issues in the newly generated files.\n\n</InlineNotification>\n\nRunning the above commands should get you the folder structure below:\n\n```bash\nsrc/app/info\n└──info.module.ts\n└──info-card\n\t├──info-card.component.scss\n\t├──info-card.component.ts\n\t├──info-card.component.spec.ts\n\t└──info-card.component.html\n└──info-section\n\t├──info-section.component.scss\n\t├──info-section.component.ts\n\t├──info-section.component.spec.ts\n\t└──info-section.component.html\n```\n\nNow let's create a JSON file that'll include our content to be shown in the components:\n\n```json path=src/app/info/info.json\n{\n  \"title\": \"The Principles\",\n  \"items\": [\n    {\n      \"heading\": \"Carbon is Open\",\n      \"content\": \"It's a distributed effort, guided by the principles of the open-source movement. Carbon's users are also it's makers, and everyone is encouraged to contribute.\"\n    },\n    {\n      \"heading\": \"Carbon is Modular\",\n      \"content\": \"Carbon's modularity ensures maximum flexibility in execution. It's components are designed to work seamlessly with each other, in whichever combination suits the needs of the user.\"\n    },\n    {\n      \"heading\": \"Carbon is Consistent\",\n      \"content\": \"Based on the comprehensive IBM Design Language, every element and component of Carbon was designed from the ground up to work elegantly together to ensure consistent, cohesive user experiences.\"\n    }\n  ]\n}\n```\n\nNow we also need to tell typescript to resolve JSON files as modules when compiling:\n\n```json path=src/tsconfig.app.json\n{\n\t\"compilerOptions\": {\n\t\t\"sourceMap\": true,\n\t\t\"declaration\": false,\n\t\t...\n\t\t\"resolveJsonModule\": true\n\t},\n\t...\n}\n```\n\n### InfoSection component\n\nLet's create the parent component that includes the \"The Principles\" heading. That markup currently looks like this in `landing-page.component.html`:\n\n```html path=src/app/home/landing-page/landing-page.component.html\n<div ibmRow class=\"landing-page__r3\">\n  <div ibmCol [columnNumbers]=\"{'md': 4, 'lg': 4}\">\n    <h3 class=\"landing-page__label\">The Principles</h3>\n  </div>\n  <div ibmCol [columnNumbers]=\"{'md': 4, 'lg': 4}\">Carbon is Open</div>\n  <div ibmCol [columnNumbers]=\"{'md': 4, 'lg': 4}\">Carbon is Modular</div>\n  <div ibmCol [columnNumbers]=\"{'md': 4, 'lg': 4}\">Carbon is Consistent</div>\n</div>\n```\n\nWe want to do a few things when abstracting it to a component. Firstly, we want to encapsulate the component's styles within it's dedicated stylesheet. We don't want to include `landing-page__r3` within the component template as that's specific to the landing page. In order to allow the landing page to have access to styling this specific instance of an `InfoSection` component we could pass the class into the instance of the component. However, we won't need to do any additional styling from the `landing-page` so we can just go ahead use the component as is.\n\nWe'll also:\n\n- Add component class names like `.info-section` and `.info-section__heading`\n- Semantically use `<section>` instead of `<div>`\n- Update the grid columns to match the design\n- Update the component content to use `info.json`\n- Replace columns 2 - 4 with `InfoCard` components\n- Remove class styling from `landing-page` component\n\n```html path=src/app/home/landing-page/landing-page.component.html\n<app-info-section></app-info-section>\n```\n\n```html path=src/app/info/info-section/info-section.component.html\n<section ibmRow class=\"info-section info-section__r1\">\n  <div ibmCol [columnNumbers]=\"{'md': 8, 'lg': 4}\">\n    <h3 class=\"info-section__heading\">The Principles</h3>\n  </div>\n  <app-info-card ibmCol [columnNumbers]=\"{'md': 4, 'lg': 4}\"> </app-info-card>\n  <app-info-card ibmCol [columnNumbers]=\"{'md': 4, 'lg': 4}\"> </app-info-card>\n  <app-info-card ibmCol [columnNumbers]=\"{'md': 4, 'lg': 4}\"> </app-info-card>\n</section>\n```\n\nAs you can see we've added instances of the `InfoCard` component. There is a few things that we need to do to resolve the errors in the browser. Firstly we need to update `InfoModule` to be able to use the `GridModule`. At the same time we will export the `InfoSection` and `InfoCard` components from the `InfoModule` so that we can use them in the `HomeModule` components (specifically `landing-page`).\n\n```ts path=src/app/info/info.module.ts\nimport { NgModule } from \"@angular/core\";\n...\nimport { GridModule } from \"carbon-components-angular\";\n\n\n@NgModule({\n\tdeclarations: [InfoCardComponent, InfoSectionComponent],\n\timports: [\n\t\tCommonModule,\n\t\tGridModule\n\t],\n\texports:  [InfoCardComponent, InfoSectionComponent]\n})\nexport class InfoModule { }\n\n```\n\nWe also need to import `InfoModule` into `HomeModule` otherwise we cannot use the `InfoSection` component within `landing-page`.\n\n```ts path=src/app/home/home.module.ts\n...\nimport { InfoModule } from \"./../info/info.module\";\nimport {\n\tBreadcrumbModule,\n\tButtonModule,\n\tGridModule,\n\tTabsModule\n} from \"carbon-components-angular\";\n\n@NgModule({\n\tdeclarations: [LandingPageComponent],\n\timports: [\n\t\tCommonModule,\n    ...\n\t\tTabsModule,\n\t\tInfoModule\n\t]\n})\nexport class HomeModule { }\n```\n\nNow we're going to go into the `InfoSection` component to add content from `info.json`.\n\n<!-- prettier-ignore-end -->\n\n```ts path=src/app/info/info-section/info-section.component.ts\nimport { Component, OnInit } from '@angular/core';\nimport * as data from '../info.json';\n\n@Component({\n  selector: 'app-info-section',\n  templateUrl: './info-section.component.html',\n  styleUrls: ['./info-section.component.scss'],\n})\nexport class InfoSectionComponent implements OnInit {\n  heading = data.title;\n  items = data.items;\n\n  constructor() {}\n\n  ngOnInit() {}\n}\n```\n\n<!-- prettier-ignore-start -->\n\nWe essentially have added a `heading` and `items` variable into the model of `InfoSectionComponent`, which we'll be using later to pass content into the children components `InfoCard`.\n\nWe've also added class names that are specific to this component that we'll target in our stylesheet:\n\n<!-- prettier-ignore-start -->\n```scss path=src/app/info/info-section/info-section.component.scss\n@import \"~carbon-components/scss/globals/scss/typography\";\n@import \"~carbon-components/scss/globals/scss/vendor/@carbon/type/scss/font-family\";\n\n@mixin info-section-background() {\n  background-color: $ui-01;\n  position: relative;\n\n  &::before {\n    content: '';\n    position: absolute;\n    left: -$spacing-05;\n    top: 0;\n    right: -$spacing-05;\n    bottom: 0;\n    background: $ui-01;\n    z-index: -1;\n  }\n}\n\n.info-section {\n  @include info-section-background;\n  display: flex;\n  height: fit-content;\n\n  &.info-section__r1 {\n    padding-top: $spacing-09;\n    padding-bottom: $spacing-09;\n    height: auto;\n  }\n\n  .info-section__heading {\n    @include carbon--type-style(\"heading-01\");\n    @include carbon--font-weight(\"semibold\");\n  }\n}\n```\n<!-- prettier-ignore-end -->\n\n### InfoCard component\n\nNext up we're going to build a component for columns 2 - 4, which currently looks like `<div ibmCol [columnNumbers]=\"{'md': 4, 'lg': 4}\">Carbon is Open</div>`. We've added the data into the parent component but we have not told `snfo-section` component to give any data to the `InfoCard` because we first need to tell `InfoCard` that it will have data to display. In `src/app/info/info-card/info-card.component.html`, add:\n\n```html path=src/app/info/info-card/info-card.component.html\n<div class=\"info-card\">\n  <h4 class=\"info-card__heading\">\n    {{heading}}\n  </h4>\n  <div class=\"info-card__body\">{{content}}</div>\n</div>\n```\n\nNow we've setup our `InfoCard` to display a heading and some content. We will setup the component `.ts` file to accept a `heading` and `content` input to be displayed.\n\n<!-- prettier-ignore-start -->\n```ts path=src/app/info/info-card/info-card.component.ts\nimport { Component, OnInit, Input } from \"@angular/core\";\n\n@Component({\n  selector: \"app-info-card\",\n  templateUrl: \"./info-card.component.html\",\n  styleUrls: [\"./info-card.component.scss\"],\n})\nexport class InfoCardComponent implements OnInit {\n  @Input() heading;\n  @Input() content;\n\n  constructor() {}\n\n  ngOnInit() {}\n}\n```\n<!-- prettier-ignore-end -->\n\nFinally, we'll update `InfoSection` to use the new `InfoCard` component.\n\n```html path=src/app/info/info-section/info-section.component.html\n<section ibmRow class=\"info-section info-section__r1\">\n  <div ibmCol [columnNumbers]=\"{'md': 4, 'lg': 4}\">\n    <h3 class=\"info-section__heading\">{{heading}}</h3>\n  </div>\n  <app-info-card\n    ibmCol\n    [columnNumbers]=\"{'md': 4, 'lg': 4}\"\n    [heading]=\"items[0].heading\"\n    [content]=\"items[0].content\"\n  >\n  </app-info-card>\n  <app-info-card\n    ibmCol\n    [columnNumbers]=\"{'md': 4, 'lg': 4}\"\n    [heading]=\"items[1].heading\"\n    [content]=\"items[1].content\"\n  >\n  </app-info-card>\n  <app-info-card\n    ibmCol\n    [columnNumbers]=\"{'md': 4, 'lg': 4}\"\n    [heading]=\"items[2].heading\"\n    [content]=\"items[2].content\"\n  >\n  </app-info-card>\n</section>\n```\n\n## Use components\n\nNext we're going to use Carbon Icon components in our custom components. We're going to place the icons within the `InfoCard` components as children. In the `InfoModule` we will import the modules we need for the Carbon Angular Icons:\n\n<!-- prettier-ignore-start -->\n```ts path=src/info/info.module.ts\nimport { NgModule } from \"@angular/core\";\n...\n\nimport { PersonFavorite32Module } from \"@carbon/icons-angular/lib/person--favorite/32\";\nimport { Globe32Module } from \"@carbon/icons-angular/lib/globe/32\";\nimport { Application32Module } from \"@carbon/icons-angular/lib/application/32\";\n\nimport { GridModule } from \"carbon-components-angular\";\n\n@NgModule({\n  declarations: [InfoSectionComponent, InfoCardComponent],\n  imports: [\n    ...\n    PersonFavorite32Module,\n    Globe32Module,\n    Application32Module,\n  ],\n  exports: [InfoSectionComponent, InfoCardComponent],\n})\nexport class InfoModule {}\n```\n<!-- prettier-ignore-end -->\n\nNext we will use `<ng-content>` so that we can inject icons into the `InfoCard` from it's parent component (`InfoSection`)\n\n```html path=src/app/info/info-card/info-card.component.html\n<div class=\"info-card\">\n  ...\n  <div class=\"info-card__body\">{{content}}</div>\n  <div class=\"info-card__icon\">\n    <ng-content></ng-content>\n  </div>\n</div>\n```\n\nWe also need to update `InfoSection` with the icon components:\n\n```html path=src/app/info/info-section/info-section.component.html\n<section ibmRow class=\"info-section info-section__r1\">\n  <div ibmCol [columnNumbers]=\"{'md': 4, 'lg': 4}\">\n    <h3 class=\"info-section__heading\">{{heading}}</h3>\n  </div>\n  <app-info-card\n    ibmCol\n    [columnNumbers]=\"{'md': 4, 'lg': 4}\"\n    [heading]=\"items[0].heading\"\n    [content]=\"items[0].content\"\n  >\n    <ibm-icon-person-favorite32></ibm-icon-person-favorite32>\n  </app-info-card>\n  <app-info-card\n    ibmCol\n    [columnNumbers]=\"{'md': 4, 'lg': 4}\"\n    [heading]=\"items[1].heading\"\n    [content]=\"items[1].content\"\n  >\n    <ibm-icon-application32></ibm-icon-application32>\n  </app-info-card>\n  <app-info-card\n    ibmCol\n    [columnNumbers]=\"{'md': 4, 'lg': 4}\"\n    [heading]=\"items[2].heading\"\n    [content]=\"items[2].content\"\n  >\n    <ibm-icon-globe32></ibm-icon-globe32>\n  </app-info-card>\n</section>\n```\n\n## Add styling\n\nWe currently have the components displaying the content we created. We need to add more styling for Carbon breakpoints, icon alignments, as well as the `InfoCard` title styling.\n\n![Info section spacing](../shared/step-4/images/info-spacing.png)\n\n### Layout\n\nStarting with layout, add the following to `src/app/info/info-card/info-card.component.scss`.\n\n<!-- prettier-ignore-start -->\n```scss path=src/app/info/info-card/info-card.component.scss\n@import \"~carbon-components/scss/globals/scss/typography\";\n@import \"~carbon-components/scss/globals/scss/layout\";\n\n.info-card {\n  display: flex;\n  flex-direction: column;\n\n  .info-card__heading {\n    @include carbon--type-style(\"productive-heading-03\");\n  }\n\n  .info-card__body {\n    margin-top: $spacing-06;\n    flex-grow: 1;\n    @include type-style(\"body-long-01\");\n\n    // prevent large line lengths between small and medium viewports\n    @include carbon--breakpoint-between(321px, md) {\n      max-width: 75%;\n    }\n  }\n}\n```\n<!-- prettier-ignore-end -->\n\nOnce you save, go ahead and resize your browser to see the responsive layout at the different breakpoints. Make sure to review these color and spacing tokens. There are also a few breakpoint mixins that may be new to you. The `@carbon/layout` [SassDoc](https://github.com/carbon-design-system/carbon/blob/master/packages/layout/docs/sass.md) is a great reference to see what all is available.\n\n### Type\n\nOur `InfoCard` headings have to be updated to match the specs. We need to make the last word of each heading bold. Add the below custom function (`createArrayFromPhrase`) to `src/app/info/info-card/info-card.component.ts`:\n\n<!-- prettier-ignore-start -->\n```ts path=src/app/info/info-card/info-card.component.ts\nimport { Component, OnInit, Input } from '@angular/core';\n\n@Component({\n  selector: \"app-info-card\",\n  templateUrl: \"./info-card.component.html\",\n  styleUrls: [\"./info-card.component.scss\"],\n})\nexport class InfoCardComponent implements OnInit {\n  @Input() heading;\n  @Input() content;\n  splitHeading;\n\n  constructor() {}\n\n  ngOnInit() {\n    // create the split title to get bold styles\n    this.splitHeading = this.createArrayFromPhrase(this.heading);\n  }\n\n  // Take in a phrase and separate the third word in an array\n  createArrayFromPhrase(phrase) {\n    const splitPhrase = phrase.split(\" \");\n    const thirdWord = splitPhrase.pop();\n    return [splitPhrase.join(\" \"), thirdWord];\n  }\n}\n```\n<!-- prettier-ignore-end -->\n\nThis'll allow us to still accept `heading` as an input to the component, but we'll need to change the template to use `splitHeading` rather than `heading` to display our heading content.\n\nUpdate the component template to use `splitHeading`:\n\n```html path=src/app/info/info-card/info-card.component.html\n<div class=\"info-card\">\n  <h4 class=\"info-card__heading\">\n    {{splitHeading[0]}}\n    <strong>{{splitHeading[1]}}</strong>\n  </h4>\n  <div class=\"info-card__body\">{{content}}</div>\n  <div class=\"info-card__icon\">\n    <ng-content></ng-content>\n  </div>\n</div>\n```\n\nThen, add some styling for the icons within our `InfoCard` component:\n\n<!-- prettier-ignore-start -->\n```scss path=src/app/info/info-card/info-card.component.scss\n@import \"~carbon-components/scss/globals/scss/typography\";\n@import \"~carbon-components/scss/globals/scss/layout\";\n\n.info-card {\n  ... .info-card__icon {\n    margin-top: $spacing-09;\n  }\n}\n```\n<!-- prettier-ignore-end -->\n\nFinally, we need styles for the `InfoCard` borders. We will use the `InfoSection` to apply styles using the children selectors. Update the `InfoSection` stylesheet to include styles targeting the `InfoCard`:\n\n```scss path=src/app/info/info-section/info-section.component.scss\n.info-section {\n  ... app-info-card {\n    margin-top: $spacing-09;\n  }\n\n  // top border in only small breakpoints to prevent overrides\n  @include carbon--breakpoint-down(md) {\n    app-info-card:not(:nth-child(2)) {\n      border-top: 1px solid $ui-03;\n      padding-top: $spacing-09;\n    }\n  }\n\n  // left border in just the 2nd column items\n  @include carbon--breakpoint(md) {\n    app-info-card:nth-child(odd) {\n      border-left: 1px solid $ui-03;\n    }\n  }\n\n  // left border in all items\n  @include carbon--breakpoint(lg) {\n    app-info-card {\n      margin-top: 0;\n      border-left: 1px solid $ui-03;\n    }\n  }\n}\n```\n\n## Submit pull request\n\nWe're going to submit a pull request to verify completion of this tutorial step.\n\n### Git commit and push\n\nBefore we can create a pull request, stage and commit all of your changes:\n\n```bash\ngit add --all && git commit -m \"feat(tutorial): complete step 4\"\n```\n\nThen, push to your repository:\n\n```bash\ngit push origin angular-step-4\n```\n\n<InlineNotification>\n\n**Note:** Having issues pushing your changes? [Step 1](/tutorial/angular/step-1#git-commit-and-push) has troubleshooting notes that may help.\n\n</InlineNotification>\n\n### Pull request (PR)\n\nFinally, visit [carbon-tutorial](https://github.com/carbon-design-system/carbon-tutorial) to \"Compare & pull request\". In doing so, make sure that you are comparing to `angular-step-4` into `base: angular-step-4`.\n\n<InlineNotification>\n\n**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!\n\n</InlineNotification>\n","type":"Mdx","contentDigest":"c23b60dcc596ccf79775d8ad9ebcb702","counter":1670,"owner":"gatsby-plugin-mdx"},"frontmatter":{"title":"4. Creating components","tabs":["Overview","Step 1","Step 2","Step 3","Step 4","Step 5","Wrapping up"]},"exports":{},"rawBody":"---\ntitle: 4. Creating components\ntabs:\n  ['Overview', 'Step 1', 'Step 2', 'Step 3', 'Step 4', 'Step 5', 'Wrapping up']\n---\n\nimport Preview from 'components/Preview';\n\n### 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.\n\n<AnchorLinks>\n\n<AnchorLink>Fork, clone and branch</AnchorLink>\n<AnchorLink>Review design</AnchorLink>\n<AnchorLink>Create components</AnchorLink>\n<AnchorLink>Use components</AnchorLink>\n<AnchorLink>Add styling</AnchorLink>\n<AnchorLink>Check accessibility</AnchorLink>\n<AnchorLink>Submit pull request</AnchorLink>\n\n</AnchorLinks>\n\n## Preview\n\nCarbon 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.\n\nNext, we're going to use Carbon assets to build application-specific components. We'll create our components with considerations for accessibility and responsiveness.\n\nA [preview](https://angular-step-5-carbon-tutorial.netlify.com) of what you'll build (see bottom of page):\n\n<Preview\n  height=\"400\"\n  title=\"Carbon Angular Tutorial Step 4\"\n  src=\"https://angular-step-5-carbon-tutorial.netlify.com\"\n  frameborder=\"no\"\n  allowtransparency=\"true\"\n  allowfullscreen=\"true\"\n/>\n\n<InlineNotification>\n\n**Note:** If you get lint errors when you copy the code from the snippets, run `ng lint --fix` to fix them.\n\n</InlineNotification>\n\n## Fork, clone and branch\n\nThis tutorial has an accompanying GitHub repository called [carbon-tutorial-angular](https://github.com/carbon-design-system/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](/tutorial/angular/step-1#fork-clone--branch).\n\n### Branch\n\nWith your repository all set up, let's check out the branch for this tutorial step's starting point.\n\n```bash\ngit fetch upstream\ngit checkout -b angular-step-4 upstream/angular-step-4\n```\n\n<InlineNotification>\n\n**Note:** This builds on top of step 3, but be sure to check out the upstream step 4 branch because it includes the static assets required to get through this step.\n\n</InlineNotification>\n\n### Build and start app\n\nInstall the app's dependencies (in case you're starting fresh in your current directory and not continuing from the previous step):\n\n```bash\nnpm install\n```\n\nThen, start the app:\n\n```bash\nnpm start\n```\n\nYou should see something similar to where the [previous step](/tutorial/angular/step-3) left off.\n\n## Review design\n\nHere'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 resusable component. As for naming, we'll call it an `InfoSection` with three `InfoCard`s as children.\n\n![Info section layout](../shared/step-4/images/info-layout.png)\n\n<Caption>Info section layout</Caption>\n\n## Create components\n\nFirst we need files for the components, so create an `Info` 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:\n\n### Generate modules & components using the Angular CLI\n\nLet's generate a new module that'll handle our `InfoCard` and `InfoSection` components:\n\n```bash\nng generate module info\n```\n\nNow we generate our `InfoCard` and `InfoSection` components:\n\n```bash\nng generate component info/info-card --lint-fix\n```\n\n```bash\nng generate component info/info-section --lint-fix\n```\n\n<InlineNotification>\n\n**Note:** The `--lint-fix` flag will automatically resolve lint issues in the newly generated files.\n\n</InlineNotification>\n\nRunning the above commands should get you the folder structure below:\n\n```bash\nsrc/app/info\n└──info.module.ts\n└──info-card\n\t├──info-card.component.scss\n\t├──info-card.component.ts\n\t├──info-card.component.spec.ts\n\t└──info-card.component.html\n└──info-section\n\t├──info-section.component.scss\n\t├──info-section.component.ts\n\t├──info-section.component.spec.ts\n\t└──info-section.component.html\n```\n\nNow let's create a JSON file that'll include our content to be shown in the components:\n\n```json path=src/app/info/info.json\n{\n  \"title\": \"The Principles\",\n  \"items\": [\n    {\n      \"heading\": \"Carbon is Open\",\n      \"content\": \"It's a distributed effort, guided by the principles of the open-source movement. Carbon's users are also it's makers, and everyone is encouraged to contribute.\"\n    },\n    {\n      \"heading\": \"Carbon is Modular\",\n      \"content\": \"Carbon's modularity ensures maximum flexibility in execution. It's components are designed to work seamlessly with each other, in whichever combination suits the needs of the user.\"\n    },\n    {\n      \"heading\": \"Carbon is Consistent\",\n      \"content\": \"Based on the comprehensive IBM Design Language, every element and component of Carbon was designed from the ground up to work elegantly together to ensure consistent, cohesive user experiences.\"\n    }\n  ]\n}\n```\n\nNow we also need to tell typescript to resolve JSON files as modules when compiling:\n\n```json path=src/tsconfig.app.json\n{\n\t\"compilerOptions\": {\n\t\t\"sourceMap\": true,\n\t\t\"declaration\": false,\n\t\t...\n\t\t\"resolveJsonModule\": true\n\t},\n\t...\n}\n```\n\n### InfoSection component\n\nLet's create the parent component that includes the \"The Principles\" heading. That markup currently looks like this in `landing-page.component.html`:\n\n```html path=src/app/home/landing-page/landing-page.component.html\n<div ibmRow class=\"landing-page__r3\">\n  <div ibmCol [columnNumbers]=\"{'md': 4, 'lg': 4}\">\n    <h3 class=\"landing-page__label\">The Principles</h3>\n  </div>\n  <div ibmCol [columnNumbers]=\"{'md': 4, 'lg': 4}\">Carbon is Open</div>\n  <div ibmCol [columnNumbers]=\"{'md': 4, 'lg': 4}\">Carbon is Modular</div>\n  <div ibmCol [columnNumbers]=\"{'md': 4, 'lg': 4}\">Carbon is Consistent</div>\n</div>\n```\n\nWe want to do a few things when abstracting it to a component. Firstly, we want to encapsulate the component's styles within it's dedicated stylesheet. We don't want to include `landing-page__r3` within the component template as that's specific to the landing page. In order to allow the landing page to have access to styling this specific instance of an `InfoSection` component we could pass the class into the instance of the component. However, we won't need to do any additional styling from the `landing-page` so we can just go ahead use the component as is.\n\nWe'll also:\n\n- Add component class names like `.info-section` and `.info-section__heading`\n- Semantically use `<section>` instead of `<div>`\n- Update the grid columns to match the design\n- Update the component content to use `info.json`\n- Replace columns 2 - 4 with `InfoCard` components\n- Remove class styling from `landing-page` component\n\n```html path=src/app/home/landing-page/landing-page.component.html\n<app-info-section></app-info-section>\n```\n\n```html path=src/app/info/info-section/info-section.component.html\n<section ibmRow class=\"info-section info-section__r1\">\n  <div ibmCol [columnNumbers]=\"{'md': 8, 'lg': 4}\">\n    <h3 class=\"info-section__heading\">The Principles</h3>\n  </div>\n  <app-info-card ibmCol [columnNumbers]=\"{'md': 4, 'lg': 4}\"> </app-info-card>\n  <app-info-card ibmCol [columnNumbers]=\"{'md': 4, 'lg': 4}\"> </app-info-card>\n  <app-info-card ibmCol [columnNumbers]=\"{'md': 4, 'lg': 4}\"> </app-info-card>\n</section>\n```\n\nAs you can see we've added instances of the `InfoCard` component. There is a few things that we need to do to resolve the errors in the browser. Firstly we need to update `InfoModule` to be able to use the `GridModule`. At the same time we will export the `InfoSection` and `InfoCard` components from the `InfoModule` so that we can use them in the `HomeModule` components (specifically `landing-page`).\n\n```ts path=src/app/info/info.module.ts\nimport { NgModule } from \"@angular/core\";\n...\nimport { GridModule } from \"carbon-components-angular\";\n\n\n@NgModule({\n\tdeclarations: [InfoCardComponent, InfoSectionComponent],\n\timports: [\n\t\tCommonModule,\n\t\tGridModule\n\t],\n\texports:  [InfoCardComponent, InfoSectionComponent]\n})\nexport class InfoModule { }\n\n```\n\nWe also need to import `InfoModule` into `HomeModule` otherwise we cannot use the `InfoSection` component within `landing-page`.\n\n```ts path=src/app/home/home.module.ts\n...\nimport { InfoModule } from \"./../info/info.module\";\nimport {\n\tBreadcrumbModule,\n\tButtonModule,\n\tGridModule,\n\tTabsModule\n} from \"carbon-components-angular\";\n\n@NgModule({\n\tdeclarations: [LandingPageComponent],\n\timports: [\n\t\tCommonModule,\n    ...\n\t\tTabsModule,\n\t\tInfoModule\n\t]\n})\nexport class HomeModule { }\n```\n\nNow we're going to go into the `InfoSection` component to add content from `info.json`.\n\n<!-- prettier-ignore-end -->\n\n```ts path=src/app/info/info-section/info-section.component.ts\nimport { Component, OnInit } from '@angular/core';\nimport * as data from '../info.json';\n\n@Component({\n  selector: 'app-info-section',\n  templateUrl: './info-section.component.html',\n  styleUrls: ['./info-section.component.scss'],\n})\nexport class InfoSectionComponent implements OnInit {\n  heading = data.title;\n  items = data.items;\n\n  constructor() {}\n\n  ngOnInit() {}\n}\n```\n\n<!-- prettier-ignore-start -->\n\nWe essentially have added a `heading` and `items` variable into the model of `InfoSectionComponent`, which we'll be using later to pass content into the children components `InfoCard`.\n\nWe've also added class names that are specific to this component that we'll target in our stylesheet:\n\n<!-- prettier-ignore-start -->\n```scss path=src/app/info/info-section/info-section.component.scss\n@import \"~carbon-components/scss/globals/scss/typography\";\n@import \"~carbon-components/scss/globals/scss/vendor/@carbon/type/scss/font-family\";\n\n@mixin info-section-background() {\n  background-color: $ui-01;\n  position: relative;\n\n  &::before {\n    content: '';\n    position: absolute;\n    left: -$spacing-05;\n    top: 0;\n    right: -$spacing-05;\n    bottom: 0;\n    background: $ui-01;\n    z-index: -1;\n  }\n}\n\n.info-section {\n  @include info-section-background;\n  display: flex;\n  height: fit-content;\n\n  &.info-section__r1 {\n    padding-top: $spacing-09;\n    padding-bottom: $spacing-09;\n    height: auto;\n  }\n\n  .info-section__heading {\n    @include carbon--type-style(\"heading-01\");\n    @include carbon--font-weight(\"semibold\");\n  }\n}\n```\n<!-- prettier-ignore-end -->\n\n### InfoCard component\n\nNext up we're going to build a component for columns 2 - 4, which currently looks like `<div ibmCol [columnNumbers]=\"{'md': 4, 'lg': 4}\">Carbon is Open</div>`. We've added the data into the parent component but we have not told `snfo-section` component to give any data to the `InfoCard` because we first need to tell `InfoCard` that it will have data to display. In `src/app/info/info-card/info-card.component.html`, add:\n\n```html path=src/app/info/info-card/info-card.component.html\n<div class=\"info-card\">\n  <h4 class=\"info-card__heading\">\n    {{heading}}\n  </h4>\n  <div class=\"info-card__body\">{{content}}</div>\n</div>\n```\n\nNow we've setup our `InfoCard` to display a heading and some content. We will setup the component `.ts` file to accept a `heading` and `content` input to be displayed.\n\n<!-- prettier-ignore-start -->\n```ts path=src/app/info/info-card/info-card.component.ts\nimport { Component, OnInit, Input } from \"@angular/core\";\n\n@Component({\n  selector: \"app-info-card\",\n  templateUrl: \"./info-card.component.html\",\n  styleUrls: [\"./info-card.component.scss\"],\n})\nexport class InfoCardComponent implements OnInit {\n  @Input() heading;\n  @Input() content;\n\n  constructor() {}\n\n  ngOnInit() {}\n}\n```\n<!-- prettier-ignore-end -->\n\nFinally, we'll update `InfoSection` to use the new `InfoCard` component.\n\n```html path=src/app/info/info-section/info-section.component.html\n<section ibmRow class=\"info-section info-section__r1\">\n  <div ibmCol [columnNumbers]=\"{'md': 4, 'lg': 4}\">\n    <h3 class=\"info-section__heading\">{{heading}}</h3>\n  </div>\n  <app-info-card\n    ibmCol\n    [columnNumbers]=\"{'md': 4, 'lg': 4}\"\n    [heading]=\"items[0].heading\"\n    [content]=\"items[0].content\"\n  >\n  </app-info-card>\n  <app-info-card\n    ibmCol\n    [columnNumbers]=\"{'md': 4, 'lg': 4}\"\n    [heading]=\"items[1].heading\"\n    [content]=\"items[1].content\"\n  >\n  </app-info-card>\n  <app-info-card\n    ibmCol\n    [columnNumbers]=\"{'md': 4, 'lg': 4}\"\n    [heading]=\"items[2].heading\"\n    [content]=\"items[2].content\"\n  >\n  </app-info-card>\n</section>\n```\n\n## Use components\n\nNext we're going to use Carbon Icon components in our custom components. We're going to place the icons within the `InfoCard` components as children. In the `InfoModule` we will import the modules we need for the Carbon Angular Icons:\n\n<!-- prettier-ignore-start -->\n```ts path=src/info/info.module.ts\nimport { NgModule } from \"@angular/core\";\n...\n\nimport { PersonFavorite32Module } from \"@carbon/icons-angular/lib/person--favorite/32\";\nimport { Globe32Module } from \"@carbon/icons-angular/lib/globe/32\";\nimport { Application32Module } from \"@carbon/icons-angular/lib/application/32\";\n\nimport { GridModule } from \"carbon-components-angular\";\n\n@NgModule({\n  declarations: [InfoSectionComponent, InfoCardComponent],\n  imports: [\n    ...\n    PersonFavorite32Module,\n    Globe32Module,\n    Application32Module,\n  ],\n  exports: [InfoSectionComponent, InfoCardComponent],\n})\nexport class InfoModule {}\n```\n<!-- prettier-ignore-end -->\n\nNext we will use `<ng-content>` so that we can inject icons into the `InfoCard` from it's parent component (`InfoSection`)\n\n```html path=src/app/info/info-card/info-card.component.html\n<div class=\"info-card\">\n  ...\n  <div class=\"info-card__body\">{{content}}</div>\n  <div class=\"info-card__icon\">\n    <ng-content></ng-content>\n  </div>\n</div>\n```\n\nWe also need to update `InfoSection` with the icon components:\n\n```html path=src/app/info/info-section/info-section.component.html\n<section ibmRow class=\"info-section info-section__r1\">\n  <div ibmCol [columnNumbers]=\"{'md': 4, 'lg': 4}\">\n    <h3 class=\"info-section__heading\">{{heading}}</h3>\n  </div>\n  <app-info-card\n    ibmCol\n    [columnNumbers]=\"{'md': 4, 'lg': 4}\"\n    [heading]=\"items[0].heading\"\n    [content]=\"items[0].content\"\n  >\n    <ibm-icon-person-favorite32></ibm-icon-person-favorite32>\n  </app-info-card>\n  <app-info-card\n    ibmCol\n    [columnNumbers]=\"{'md': 4, 'lg': 4}\"\n    [heading]=\"items[1].heading\"\n    [content]=\"items[1].content\"\n  >\n    <ibm-icon-application32></ibm-icon-application32>\n  </app-info-card>\n  <app-info-card\n    ibmCol\n    [columnNumbers]=\"{'md': 4, 'lg': 4}\"\n    [heading]=\"items[2].heading\"\n    [content]=\"items[2].content\"\n  >\n    <ibm-icon-globe32></ibm-icon-globe32>\n  </app-info-card>\n</section>\n```\n\n## Add styling\n\nWe currently have the components displaying the content we created. We need to add more styling for Carbon breakpoints, icon alignments, as well as the `InfoCard` title styling.\n\n![Info section spacing](../shared/step-4/images/info-spacing.png)\n\n### Layout\n\nStarting with layout, add the following to `src/app/info/info-card/info-card.component.scss`.\n\n<!-- prettier-ignore-start -->\n```scss path=src/app/info/info-card/info-card.component.scss\n@import \"~carbon-components/scss/globals/scss/typography\";\n@import \"~carbon-components/scss/globals/scss/layout\";\n\n.info-card {\n  display: flex;\n  flex-direction: column;\n\n  .info-card__heading {\n    @include carbon--type-style(\"productive-heading-03\");\n  }\n\n  .info-card__body {\n    margin-top: $spacing-06;\n    flex-grow: 1;\n    @include type-style(\"body-long-01\");\n\n    // prevent large line lengths between small and medium viewports\n    @include carbon--breakpoint-between(321px, md) {\n      max-width: 75%;\n    }\n  }\n}\n```\n<!-- prettier-ignore-end -->\n\nOnce you save, go ahead and resize your browser to see the responsive layout at the different breakpoints. Make sure to review these color and spacing tokens. There are also a few breakpoint mixins that may be new to you. The `@carbon/layout` [SassDoc](https://github.com/carbon-design-system/carbon/blob/master/packages/layout/docs/sass.md) is a great reference to see what all is available.\n\n### Type\n\nOur `InfoCard` headings have to be updated to match the specs. We need to make the last word of each heading bold. Add the below custom function (`createArrayFromPhrase`) to `src/app/info/info-card/info-card.component.ts`:\n\n<!-- prettier-ignore-start -->\n```ts path=src/app/info/info-card/info-card.component.ts\nimport { Component, OnInit, Input } from '@angular/core';\n\n@Component({\n  selector: \"app-info-card\",\n  templateUrl: \"./info-card.component.html\",\n  styleUrls: [\"./info-card.component.scss\"],\n})\nexport class InfoCardComponent implements OnInit {\n  @Input() heading;\n  @Input() content;\n  splitHeading;\n\n  constructor() {}\n\n  ngOnInit() {\n    // create the split title to get bold styles\n    this.splitHeading = this.createArrayFromPhrase(this.heading);\n  }\n\n  // Take in a phrase and separate the third word in an array\n  createArrayFromPhrase(phrase) {\n    const splitPhrase = phrase.split(\" \");\n    const thirdWord = splitPhrase.pop();\n    return [splitPhrase.join(\" \"), thirdWord];\n  }\n}\n```\n<!-- prettier-ignore-end -->\n\nThis'll allow us to still accept `heading` as an input to the component, but we'll need to change the template to use `splitHeading` rather than `heading` to display our heading content.\n\nUpdate the component template to use `splitHeading`:\n\n```html path=src/app/info/info-card/info-card.component.html\n<div class=\"info-card\">\n  <h4 class=\"info-card__heading\">\n    {{splitHeading[0]}}\n    <strong>{{splitHeading[1]}}</strong>\n  </h4>\n  <div class=\"info-card__body\">{{content}}</div>\n  <div class=\"info-card__icon\">\n    <ng-content></ng-content>\n  </div>\n</div>\n```\n\nThen, add some styling for the icons within our `InfoCard` component:\n\n<!-- prettier-ignore-start -->\n```scss path=src/app/info/info-card/info-card.component.scss\n@import \"~carbon-components/scss/globals/scss/typography\";\n@import \"~carbon-components/scss/globals/scss/layout\";\n\n.info-card {\n  ... .info-card__icon {\n    margin-top: $spacing-09;\n  }\n}\n```\n<!-- prettier-ignore-end -->\n\nFinally, we need styles for the `InfoCard` borders. We will use the `InfoSection` to apply styles using the children selectors. Update the `InfoSection` stylesheet to include styles targeting the `InfoCard`:\n\n```scss path=src/app/info/info-section/info-section.component.scss\n.info-section {\n  ... app-info-card {\n    margin-top: $spacing-09;\n  }\n\n  // top border in only small breakpoints to prevent overrides\n  @include carbon--breakpoint-down(md) {\n    app-info-card:not(:nth-child(2)) {\n      border-top: 1px solid $ui-03;\n      padding-top: $spacing-09;\n    }\n  }\n\n  // left border in just the 2nd column items\n  @include carbon--breakpoint(md) {\n    app-info-card:nth-child(odd) {\n      border-left: 1px solid $ui-03;\n    }\n  }\n\n  // left border in all items\n  @include carbon--breakpoint(lg) {\n    app-info-card {\n      margin-top: 0;\n      border-left: 1px solid $ui-03;\n    }\n  }\n}\n```\n\n## Submit pull request\n\nWe're going to submit a pull request to verify completion of this tutorial step.\n\n### Git commit and push\n\nBefore we can create a pull request, stage and commit all of your changes:\n\n```bash\ngit add --all && git commit -m \"feat(tutorial): complete step 4\"\n```\n\nThen, push to your repository:\n\n```bash\ngit push origin angular-step-4\n```\n\n<InlineNotification>\n\n**Note:** Having issues pushing your changes? [Step 1](/tutorial/angular/step-1#git-commit-and-push) has troubleshooting notes that may help.\n\n</InlineNotification>\n\n### Pull request (PR)\n\nFinally, visit [carbon-tutorial](https://github.com/carbon-design-system/carbon-tutorial) to \"Compare & pull request\". In doing so, make sure that you are comparing to `angular-step-4` into `base: angular-step-4`.\n\n<InlineNotification>\n\n**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!\n\n</InlineNotification>\n","fileAbsolutePath":"/zeit/767b4790/src/pages/tutorial/angular/step-4.mdx"}}}}