Create, register and contextually load a custom library in Drupal 8

In this example, we will create a custom module, where we will declare a custom library, and load it based on custom parameters.

The final file structure of the module will be this:

├── angular.libraries.yml
├── angular.module
└── js
    ├── angular.min.js
    └── app.js

I will name this custom module "angular", since it will be contextually loading AngularJS, for a progressive decoupled Drupal 8 setup.

The first thing to do is to create a simple module. The best way is to use Drupal Console (drupal generate:module command).

After that, we must create a "module_name.libraries.yml" file (in our case "angular.libraries.yml"), where we will declare our library.

The contents of the "angular.libraries.yml" file will be:

  version: 1.x
    js/angular.min.js: {}
    js/app.js: {}
  1. "angularlib" is the name of our library. It can be anything we want.
  2. "js/angular.min.js" is the minified AngularJS file.
  3. "js/app.js" is the custom JavaScript file where we will create our Angular module, controller, etc.

The contents of the "js/app.js" file will be:

angular.module('app', [])
  .controller('mainCtrl', ['$scope', function ($scope) {
    $scope.message = 'Angular is working!';

The custom library is ready. Now we have to write the logic (in our "angular.module" file) for loading it contextually.

For the purpose of this tutorial, we will load the custom library only when we are looking at an "article" node.

The contents of the "angular.module" file will be:


 * @file
 * Contains angular.module..

 * Implements hook_page_attachments_alter().
function angular_page_attachments_alter(array &$attachments) {
  if (\Drupal::routeMatch()->getParameter('node') != null) {
    if (\Drupal::routeMatch()->getParameter('node')->getType() == 'article') {
      $attachments['#attached']['library'][] = 'angular/angularlib';

Next step is to add the necessary "ng-app" and "ng-controller" AngularJS directives in our "html.html.twig" template. E.g.:

<html{{ html_attributes }} data-ng-app="app">
  <!-- various stuff -->
  <body{{ attributes.addClass(body_classes) }} data-ng-controller="mainCtrl">

Enable the module.

Create a custom block with the following source code:


Set the visibility of the block to "Content types: Article", and place your block in some region.

Now, if you navigate to an article, you must see your custom block with the content: "Angular is working!"


PS: The same procedure can be done within your theme instead of a custom module.