3 min read21 hours ago
–
Press enter or click to view image in full size
AI generated image
For the last decade, accessibility in Angular was a string-typing nightmare.
If you wanted to build an accessible toggle button, you had to manually bind attributes. You wrote code like [attr.aria-presed]="isActive".
Did you spot the typo?
I wrote aria-presed instead of aria-pressed. The compiler did not catch it. The browser ignored it. And the screen reader user had no idea the button was clicked.
That era is over.
With the release of Angular 21, the team has introduced Reactive Aria Primitives. I just rewrote my entire internal UI kit using them. The result is 100% type safety and zero change detection overhead.
The Old Way: The “String” Problem
We used to trea…
3 min read21 hours ago
–
Press enter or click to view image in full size
AI generated image
For the last decade, accessibility in Angular was a string-typing nightmare.
If you wanted to build an accessible toggle button, you had to manually bind attributes. You wrote code like [attr.aria-presed]="isActive".
Did you spot the typo?
I wrote aria-presed instead of aria-pressed. The compiler did not catch it. The browser ignored it. And the screen reader user had no idea the button was clicked.
That era is over.
With the release of Angular 21, the team has introduced Reactive Aria Primitives. I just rewrote my entire internal UI kit using them. The result is 100% type safety and zero change detection overhead.
The Old Way: The “String” Problem
We used to treat ARIA as second-class citizens. We attached them to the DOM like stickers.
// The Angular 18 Way@Component({ template: `<button [attr.aria-expanded]="isOpen()">Menu</button>`})export class Menu { isOpen = signal(false);}
This works, but it is brittle. It relies on string parsing. It runs inside the template check loop.