Do you have a hard time reading the HTML of your components? You are not alone, and many factors can contribute to this. However, today I will show you a Prettier plugin that will help to organize the HTML attributes and hopefully make it easier to read and understand everything that is going on with your components.
Say hello 👋 to the prettier-plugin-organize-attributes
When using Prettier, any HTML line that is longer than the printWidth
setting will be split into multiple lines, one line for each attribute, helping to make the HTML cleaner and readable.
Having a standard order for the HTML attributes can also help us quickly find out what the most important parts of an element are since we will be used to looking for attributes in the same order in every component.
For this, we will use the pluginprettier-plugin-organize-attributes
that, fortunately, helps us set the order for HTML attributes and also supports Vue, React, and Angular.
Installing and configuring the library
Simply run the following command to install the library:
npm i prettier prettier-plugin-organize-attributes -D
Now in the prettier configuration file, add the following configuration:
attributeGroups: [
'^(id|name)$',
'$ANGULAR_STRUCTURAL_DIRECTIVE',
'^app',
'$ANGULAR_ELEMENT_REF',
'data-testid',
'tabindex',
'$ALT',
'$ARIA',
'$ROLE',
'$TYPE',
'$CLASS',
'ngClass',
'^\\[style',
'$ANGULAR_ANIMATION',
'$ANGULAR_ANIMATION_INPUT',
'^\\[attr',
'$ANGULAR_TWO_WAY_BINDING',
'$ANGULAR_INPUT',
'^(\\(blur\\)|\\(focus\\)|)$',
'^(\\(click\\)|\\(dbclick\\)|\\(submit\\))$',
'^(\\(cut\\)|\\(copy\\)|\\(paste\\))$',
'^(\\(keyup\\)|\\(keypress\\)|\\(keydown\\))$',
'^(\\(mouseup\\)|\\(mousedown\\)|\\(mouseenter\\)|\\(scroll\\))$',
'^(\\(drag\\)|\\(drop\\)|\\(dragover\\))$',
'$ANGULAR_OUTPUT'
],
Let's break out why this order was chosen so you can rearrange and adapt as you need.
Invalid Attributes
The first line'^(id|name)$',
is to bring to the top any HTML attributes that you don't allow to make it easier to find them during code reviews; in this example, id
and name
.
Directives
Since the directives also might change presentation is good to have them close to the first items to easily identify that the current HTML is affected by a directive.
With the '$ANGULAR_STRUCTURAL_DIRECTIVE',
the commonly used directives like *ngIf
and *ngFor
, as well as any directives that may alter or add additional elements to the DOM, will be the first to be shown.
Next, we show the specific selector for directives in our application, like app
with the configuration of '^app',
Test Ids
This includes any HTML attribute to select HTML elements while executing tests like data-testid
or data-cy
HTML and Angular Accessibility Attributes
The following will group everything related to accessibility
'tabindex',
'$ALT',
'$ARIA',
'$ROLE',
'$TYPE',
'^\\[attr',
Stylistic Attributes
'$CLASS',
'ngClass',
'^\\[style',
This would include any attributes that directly affect how the element is styled, such as class
, [ngStyle]
, and [ngClass]
.
After knowing that the element will be in the DOM, the next logical thing is knowing how the element will look on the page. This rule includes any conditional classes added with Angular data binding syntax like [class.some-class]="true"
, which is just an alternative to ngClass
and ngStyle
.
Inputs, outputs and DOM Events handlers
'$ANGULAR_TWO_WAY_BINDING',
'$ANGULAR_INPUT',
'^(\\(blur\\)|\\(focus\\)|)$',
'^(\\(click\\)|\\(dbclick\\)|\\(submit\\))$',
'^(\\(cut\\)|\\(copy\\)|\\(paste\\))$',
'^(\\(keyup\\)|\\(keypress\\)|\\(keydown\\))$',
'^(\\(mouseup\\)|\\(mousedown\\)|\\(mouseenter\\)|\\(scroll\\))$',
'^(\\(drag\\)|\\(drop\\)|\\(dragover\\))$',
'$ANGULAR_OUTPUT'
This includes standard element attributes, inputs, outputs, and DOM event handlers.
This configuration makes sure that all the DOM Event handlers are grouped logically to make it easier to find counterparts, like, for example, (copy)
, (cut)
and (paste)
will be close together regardless of which other outputs exist.
Finally, include any DOM event handlers, such as (mouseenter)
, (copy)
, (keyup)
, etc.
Putting it all together
Now, let's see how this will work if, instead of relying on code reviews, we change it to use the library prettier-plugin-organize-attributes
Let's give it a try in this component that has way too many attributes but that can help us see how the plugin works when the HTML element has a lot of different attribute types