Add Bootstrap to an Angular application
Older Article
This article was published 8 years ago. Some information may be outdated or no longer applicable.
Back when CSS was less tangled (think the 1990s), styling a page was relatively painless. Now there’s a lot more to wrangle. A few frameworks have emerged to solve the design problem. In this first article, we’ll cover how to bolt Bootstrap onto an Angular application. The second, follow-up article examines how to use Material Design.
No need to use both frameworks. Either one works, but their integration paths differ.
Bootstrap
Bootstrap, now on its fourth version, is one of the most widely used front-end component libraries. It gives developers a grid system, dropdowns, modals, navigation bars, progress bars and more.
To use Bootstrap in an Angular project, first scaffold an Angular application via the CLI: ng new [app-name].
Then install Bootstrap via npm: npm i bootstrap.
Bootstrap depends on Popper.js and jQuery. Install both:
npm i jquery popper.js.
We could have pulled Bootstrap in via a CDN in
index.html, but here we’re wiring it into the Angular project properly.
Setup
After installation, we need to edit the angular.json file at the project root. This JSON file holds application settings: TypeScript linter config, test settings, and (crucially) which external JavaScript and CSS files to load.
Find the path to styles and scripts (projects - project-name - architect - build) and drop in the following values:
"styles": [
"src/styles.css",
"node_modules/bootstrap/dist/css/bootstrap.min.css"
],
"scripts": [
"node_modules/jquery/dist/jquery.min.js",
"node_modules/popper.js/dist/umd/popper.min.js",
"node_modules/bootstrap/dist/js/bootstrap.min.js"
]
Order matters here. Bootstrap depends on jQuery and Popper.js, so those must come first.
One gotcha: if ng serve is already running, we need to kill it and restart. Changes to angular.json don’t propagate into a running dev server.
Example
Quick test: open index.html and drop in this HTML for a Bootstrap alert panel:
<div class="alert alert-success" role="alert">Bootstrap in action!</div>

A dependency issue
So far so good. But there’s a jQuery dependency dragging along, which adds weight to the project. It’d be better to strip that out.
Some actions also throw errors. Say we want to fire a callback when a modal closes:
$('#myModal').on('hidden.bs.modal', (event) => {
console.log('closed', event);
});
This throws:
Cannot find name '$'. Do you need to install type definitions for jQuery? Try `npm i @types/jquery`
Fine. Install the type definition for jQuery. But the same error persists.
One workaround (not ideal): declare $ with the any datatype in TypeScript: declare var $: any;
Even then, the event listener won’t fire because we need a document.ready() event too:
$(document).on('hidden.bs.modal', '#exampleModal', (event) => {
console.log('closed', event);
});
Only then does this simple piece of code actually work. There’s a better approach, and it strips out the dependencies at the same time.
ng-bootstrap and ngx-bootstrap
Both of these component libraries do the same thing: they give us Bootstrap components without jQuery, Popper.js, or the actual bootstrap.js. (A Bootstrap CSS file is still required.)
To confirm jQuery and Popper.js aren’t lurking around, uninstall them:
npm uninstall jquery popper.js, and remove the script entries fromangular.json.
ng-bootstrap
Install ng-bootstrap: npm i @ng-bootstrap/ng-bootstrap. After installation, we can either import the entire module or cherry-pick only the components we need:
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
// or:
// import { NgbAlertModule, NgbModalModule } from '@ng-bootstrap/ng-bootstrap';
@NgModule({
...
imports: [ NgbModule ],
// or:
// imports: [ NgbAlertModule, NgbModalModule],
...
})
export class YourAppModule {
}
Importing only the modules the application needs will trim the overall bundle size.
Examples
That’s it. No more setup required. Drop this into app.component.html (or any other component template, but not index.html):
<ngb-alert [dismissible]="false"> ng-boostrap in the house! </ngb-alert>
That shows an alert panel.

What about a modal with an event listener? Drop this into a component:
<ng-template #content let-modal>
<div class="modal-header">
<h4 class="modal-title" id="modal-basic-title">Profile update</h4>
<button
type="button"
class="close"
aria-label="Close"
(click)="modal.dismiss('Cross click')"
>
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p>Hello modal, looking good!</p>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-outline-dark"
(click)="modal.close('Save click')"
>
Save
</button>
</div>
</ng-template>
<button class="btn btn-lg btn-outline-primary" (click)="open(content)">
Launch demo modal
</button>
<hr />
<pre>{{ closeResult }}</pre>
And the component definition:
`import { Component } from '@angular/core';
import { NgbModal, ModalDismissReasons } from '@ng-bootstrap/ng-bootstrap';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'css-angular';
closeResult: string;
constructor(private modalService: NgbModal) { }
open(content) {
this.modalService.open(content, {ariaLabelledBy: 'modal-basic-title'}).result.then((result) => {
this.closeResult = `Closed with: ${result}`;
}, (reason) => {
this.closeResult = `Dismissed ${this.getDismissReason(reason)}`;
});
}
private getDismissReason(reason: any): string {
if (reason === ModalDismissReasons.ESC) {
return 'by pressing ESC';
} else if (reason === ModalDismissReasons.BACKDROP_CLICK) {
return 'by clicking on a backdrop';
} else {
return `with: ${reason}`;
}
}
}
We can capture the close event and print the reason why the modal was closed, all without a single jQuery or Bootstrap.js dependency.
Code sample taken from the ng-bootstrap documentation, slightly modified.
ngx-bootstrap
Like ng-bootstrap, ngx-bootstrap gives us Bootstrap components the Angular-native way, with no external JavaScript dependencies.
Install it: npm install ngx-bootstrap. Alternatively, ngx-bootstrap supports the ng add command: ng add ngx-bootstrap. The second approach also wires up the CSS in angular.json automatically, so there’s no need to manually point to Bootstrap’s stylesheet.
Next, drop the import statements into app.module.ts:
// specific import
import { AlertModule } from 'ngx-bootstrap/alert';
// generic import to import further modules:
// import { AlertModule, ModalModule } from 'ngx-bootstrap';
@NgModule({
// ...
imports: [AlertModule.forRoot(), ...]
// ...
})
Again, importing only the required modules helps trim the application’s size.
Examples
Test it by dropping an alert panel into a component template:
<alert type="success">
<p>Hello from ngx-bootstrap</p>
</alert>
If everything’s wired up correctly, a green alert should appear.

For completeness, here’s a modal with an event listener on the hide event:
<button type="button" class="btn btn-primary" (click)="openModal(template)">Create template modal</button>
<ng-template #template>
<div class="modal-header">
<h4 class="modal-title pull-left">Modal</h4>
<button type="button" class="close pull-right" aria-label="Close" (click)="modalRef.hide()">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
This is a modal.
</div>
</ng-template>
import { Component, TemplateRef } from '@angular/core';
import { BsModalService } from 'ngx-bootstrap/modal';
import { BsModalRef } from 'ngx-bootstrap/modal/bs-modal-ref.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'css-angular';
modalRef: BsModalRef;
constructor(private modalService: BsModalService) {}
openModal(template: TemplateRef<any>) {
this.modalRef = this.modalService.show(template);
this.modalService.onHide.subscribe((reason: string) => {
console.log(`onHide event has been fired`);
});
}
}
Same result, no external JavaScript library in sight.
Conclusion
Three ways to wire Bootstrap into an Angular application: natively, via ng-bootstrap, and via ngx-bootstrap. Each gets the job done; the ng-bootstrap and ngx-bootstrap routes strip out the jQuery dependency.