Assessing the Angular Material Component Library
For a long time, JavaScript has been the most popular programming language. It has become omnipresent in software development, especially within web applications — It is practically synonymous with web front-end technologies.
JavaScript runs inside the browser, and web browsers run on machines with varying operating systems. Thus, JavaScript can be considered cross-platform. This makes JavaScript quite powerful compared to other languages since it develops for devices with a wider audience than iOS apps just for Apple OS. Furthermore, it’s an easy language to learn, with fewer barriers to entry. These attributes of JS all contribute to its hall-of-fame status.
Angular is a popular JavaScript frontend framework led by Google. It is an improvement on its predecessor AngularJS and is used by household names like Netflix and the popular business magazine company Forbes, to name a few.
Angular is used to develop single-page applications (SPAs). These applications radically differ from their counterpart, namely multi-page applications (MPAs). MPAs make heavy use of the server to traverse the user throughout the application — instead of just exchanging data with the server, full pages are also sent for display on the browser. On the other hand, SPAs send and receive only application data, making them faster and feel more like native applications run on a desktop or mobile phone. SPAs are considered a modern improvement to front-end application development, which makes them well-suited for modern frameworks like React JS, Vue, Ember JavaScript framework, and of course, Angular.
Angular uses powerful concepts to implement the Model View Controller architecture. For instance, data binding for communication from the component (controller) to the template (view) separates business logic from presentation. Another central concept in Angular is components, the building blocks that make up an Angular application.
Google is also the creator of Material Design, loosely known as a specification and collection of principles and guidelines that adhere to user interface best practices. Material principles are wide-ranging: they include principles relating to textual content (typography, grids, spacing, scale, colour, imagery, etc.), principles that prescribe how motion should occur across an application, principles on how to communicate focus, selection, activation, error, hover, press, drag and disabled states, and yet even more principles and best practices — it’s a powerful component specification.
Angular Material is one of the many implementations of Google’s Material Design. Almost all major front-end frameworks (e.g., JavaScript frameworks like Facebook’s React.js, the open-source framework created by Evan You called Vue.js, etc.) have a Material Design implementation, and Angular Material is, for — you guessed it… Angular. Angular Material (AM) was created in 2014 and is still widely used today, so it can be considered an established tool for web app development.
A basic understanding of Angular is all that is needed to use most AM components since they are easy to use. It also doesn’t have a steep learning curve. Any AM component in your project will automatically adhere to design best practices (as set out by Material Design), making AM a powerful tool that supports rapid development.
AM also offers other great features. One of these is theming. AM theming allows developers to specify the styling of all components (relating to colour and typography) used across an application in just a few lines of code. One can also change the entire theme with the same effort, affecting the application everywhere these components are used, thus supporting rapid development.
AM provides tools for programmatic interaction with UI components if UI testing is desired. From my experience, this is useful when testing UI logic. Again, because of its ease of use, it supports speedy development.
AM is also customisable; however, it is only easily customisable within the confines of the Material Design guidelines. Any other customisations entail more complexity. Allow me to explain.
The AM docs state that you can safely define custom styling for a component if it affects its positioning and layout. This would include margin, position, top, left, transform and z-index. They further state that this custom styling needs to be applied to the element that hosts the AM component. From an external dependency management perspective, we can see how this protects our code from being broken by AM updates. To understand this better, we’ll look at a simple example:
Suppose we want to use the AM Select component for a typical drop-down input:
Now suppose we want to customise the left margin of this component. We do this by wrapping the AM select component in another element that we have full control over (here, just a normal <div> with class name my-custom-wrapper):
This allows us to safely specify the recommended style overrides. Now, when AM upgrades its library and changes the name of the AM Select element, it won’t break our code. If we instead did not wrap the AM component and directly targeted it, we’d be using AM’s class names which run the risk of breaking our code when AM changes. An example of this is explained below.
The docs recommend that you not define styles that affect a component’s size or internal layout. This would include padding, height, width, or overflow. This can cause your project to break if Angular Material changes something related to those styles. These types of styles cause problems because of their nature: we cannot change these styles using a wrapping element like before, so we’re forced to directly target AM components using AM class names.
AM outlines (https://material.angular.io/guide/customizing-component-styles) how one would go about doing this, so we’ll go through an example to better understand the convoluted process of overriding these specific styles.
Suppose we want to use an AM button: There are seven flavours: basic, raised, stroked, flat, icon, fab and mini-fab:
We choose the flat button:
This button looks great. But what if Design wants a button with a different border-radius, say 0 pixels? This is possible, but at a cost, since this is one of the unrecommended style changes. Now I know I said these styles include padding, height, width and overflow, and border-radius is not mentioned; however, border-radius counts as an internal style. So, it still counts as an unrecommended style change.
To override the border-radius of AM buttons, we need to (1) enter the developer console on our web application inside the browser, (2) inspect the source to view the document object model and (3) select the button that we want to change. This will show us the markup and related styling:
On the left, we can see all the class names given to the button: mat-focus-indicator, mat-flat-button, mat-button-base, mat-primary (we can ignore mat-focus-indicator and mat-button-base since they aren’t applicable).
Furthermore, on the right, we can see the class names used for the specific style we’re interested in overriding (border-radius). Here we can see that the border-radius applies to elements with a class name of either mat-button, mat-icon-button, mat-stroked-button or mat-flat-button. Here mat-flat-button is the only applicable one.
mat-primary gets applied to an element when the primary theme palette is assigned to the color attribute (e.g., color=”primary”) and mat-flat-button gets applied to a button when we use the flat button flavour (e.g., <button mat-flat-button>Button</button>).
Now, all we need to do is use our intuition to decide which class names we’re going to combine to target the button for our customisation. We’ll choose mat-flat-button since this will target all flat buttons. We’ll also use the mat-primary class to target buttons with the primary palette applied. We also add our additional class myButton, to target only this one button and not all primary-coloured flat-buttons.
Using these classes in our styling will allow us to override the applicable style that AM created:
Now a button of type (1) mat-flat-button, with the (2) color attribute set to “primary” and a (3) class name of myButton will have a border radius of 0 pixels.
Phew! I don’t know about you, but for a component library that facilitates rapid development, that sure took a lot of time and effort and left us with a lot of developer overhead.
If AM upgrades its library and change, say, the name of the AM flat-button class, it will break our code. Of course, this is very bad.
To affect the style of an AM component, we need to define it in a global stylesheet — the stylesheet specified in the “styles” array of the “angular.json” configuration file. This is the best approach since the other options are to turn off view encapsulation, which carries the burden of boilerplate code, or using the ::ng-deep combinator, which is deprecated. (https://betterprogramming.pub/best-way-to-overwrite-angular-materials-styles-e38dc8b84962). This type of style overriding is unrecommended due to the tampering of global styles since global CSS usually brings with it a whole set of challenges — another disadvantage.
The reason for making the styles global is another concept in Angular known as view encapsulation. View encapsulation is the scoping of a component’s styles to the view of only said component, making styles only affect elements that are directly in that component’s template. This means styles defined in ourcomponents will not affect AM components –Please see below for an explanation of why this is not always true (at least with AM).
A side note on view encapsulation with AM: it appears that this rule is not respected by AM’s buttons (and possibly other components too). In other words, it can override unrecommended styles without placing the styling in a global stylesheet. Observe this repo: https://stackblitz.com/github/ByronKrugr/assessing-angular?file=README.md — Notice how the button component’s internal style is overridden from anywhere (the view-encapsulated stylesheet or the global one) but how the global style only overrides the tab-group component’s style. The reason for this is unknown; however, the concept still holds for other AM components, so it is safer to stick to the rule.
In conclusion, AM is a tool associated with rapid development since components automatically adhere to user interface best practices and since it has many free features that come directly out of the box, as mentioned. However, having to go through all that trouble to achieve customisation makes the rapid development characteristic debatable.
So, what tool could one use to make up for where AM lacks? A brief research session leads to a non-exhaustive list of possible alternatives, namely, PrimeNG and NG-ZORRO. These libraries serve the same purpose as AM. However, they boast more flexibility. Going in-depth into another Angular component library is not within the scope of this article, so whether these libraries do what they say on the tin hasn’t been fully explored.
The PrimeNG component library offers much the same as Angular Material. PrimeNG’s premium features work with SCSS and allow for easy customisations via SASS. PrimeNG’s free themes are open source, and the generated CSS that comes with it is customisable too. However, complex customisation is not recommended. This is due to the complex process since it requires finding and replacing variables throughout the styling code base managed by PrimeNG (https://www.primefaces.org/primeng/setup).
To change the specific style of a certain component, it is given a class and said style is overridden (similar to how it was shown in AM). The docs also state that if a style does not take effect due to view encapsulation, then ::ng-deep is recommended, but remember that this is not a good option due to the deprecation.
https://medium.com/@centizennationwide/angular-material-vs-prime-ng-f54a7255ec95
https://www.youtube.com/watch?v=WgK9ZUXnnNA
NG-ZORRO is also a component library like AM. It implements the Ant Design specification (similar to Material Design) and is spearheaded by Alibaba. NG-ZORRO has many style variables you can interact with as opposed to AM. It allows for specifying almost anything — spacing, font size, line height, etc., so it has powerful theme customisation. This allows for a personalised brand since it facilitates making a component look different from other projects.
https://emilyxiong.medium.com/trying-out-ng-zorro-3aa529cdb8
Angular Material can still be considered an effective tool only when applied to the correct use case. If you’re working in an environment where stakeholder requirements aren’t stable and demand specific customisation, then Angular Material is a poor choice. However, it can be a powerful tool if the stakeholder is not concerned about these limitations or if quick development is desired.