If you’ve been following Angular’s journey, version 21 brings some fresh air with features that many developers have been waiting for. The long-awaited Signal Forms are finally arriving. Although they’re experimental, this feature gives a glimpse into a smoother, more reactive approach to handling forms in Angular. Meanwhile, zoneless change detection is now enabled by default, boosting the framework’s performance and making your life easier. Let’s go over some of the cool updates coming in Angular 21.
Signal Forms
Angular 21 introduces Signal Forms, an experimental but promising feature that offers a fresh, declarative, and reactive way to manage form state using signals. To better understand how Signal Forms work in practice, let’s walk through the basic steps of creating one, starting with defining your form’s state as a signal.
crewMember = signal<CrewMember>(
{
name: '',
imageUrl: '',
position: ''
}
);
crewForm = form(this.crewMember);
This setup defines a signal holding the crew member’s model. You can then pass this model to Angular’s form() function to create the reactive form tree reflecting this structure.
The next step is to bind individual signal form fields to your HTML elements using the Field directive. This directive creates a two-way binding between the input element and the form’s signal model. Any changes in the input automatically update the form state, and any updates to the model immediately reflect in the input. Using it is really straightforward: just add [field] to your input elements and assign the corresponding form field. Remember to import the Field directive in your component’s imports array; otherwise, Angular won’t recognize it.
<input type="text" [field]="crewForm.name" placeholder="Enter pirate name">
<input type="url" [field]="crewForm.imageUrl" placeholder="Enter image URL">
<input type="text" [field]="crewForm.position" placeholder="Enter crew position">
…
<!--Preview-->
<div>
<p>Name: {{ crewForm.name().value() }}</p>
<p>Position: {{ crewForm.position().value() }}</p>
</div>
<img [src]="crewMember().imageUrl">
In this example, you can see inputs bound to the crewForm fields for name, image URL, and position. Just below, there’s a live preview that shows how you can display the current form values by accessing crewForm.name().value() or crewForm.position().value(). Similarly, the image URL is read from the original crewMember signal, demonstrating how both the crewForm and the crewMember signal stay in sync.

Figure 1: Signal Form live preview
Validation
To add validation in Signal Forms, pass a schema function into the form() method. The function can include built-in validators, such as required, email, or minLength, alongside your own custom validation logic. Error messages can be customized via options, allowing friendly and precise feedback for users interacting with forms.
crewForm = form(this.crewMember, (path) => {
required(path.name, { message: 'Name is required' });
minLength(path.name, 2, { message: 'Name must be at least 2 characters long' });
required(path.position, { message: 'Position is required' });
required(path.imageUrl, { message: 'Image URL is required' });
});
To show validation errors for a form field, first check if the field has been touched (if the user has interacted with it) and is currently invalid. This prevents displaying errors like ‘required’ prematurely before the user starts typing.
You can get the list of errors for the field by accessing its errors() signal, and then display the error message.
@if(crewForm.name().touched() && crewForm.name().invalid()) {
<ul class="error-message">
@for(error of crewForm.name().errors(); track $index) {
<li>{{ error.message }}</li>
}
</ul>
}

Figure 2: Signal Form validation errors
These examples illustrate the basic usage of Signal Forms to demonstrate core concepts. Check the Angular official docs to learn more about Signal Forms and their evolving functionality. Since this is an experimental API, expect some changes, but also a bright future for building forms declaratively and reactively.
Zoneless by default
Starting with Angular 21, zoneless change detection is now enabled by default. No more Zone.js dependency. The Zoneless API has been stable since Angular 20.2, but version 21 takes it further: there’s no need to import provideZonelessChangeDetection in your app config, as all new Angular applications are now zoneless out of the box.
In a zoneless app, change detection no longer triggers automatically on every async task, like HTTP requests, observables, or timers such as setTimeout or setInterval. This is a big shift compared to how Zone.js worked. Now, change detection runs only when explicitly triggered by certain actions, including:
- Async pipe
- User-bound events like clicks or input events
- Signal value update used in the template
- markForCheck()
- call to ComponentRef.setInput()
Going zoneless breaks free from the old Zone.js magic, so change detection fires only on explicit triggers you control, avoiding unnecessary change detection cycles and resulting in better app performance. Removing Zone.js also shrinks the bundle size, which improves Core Web Vitals. Debugging gets cleaner as well, since stack traces are no longer polluted by Zone.js. For best performance, pairing zoneless mode with the OnPush strategy is highly recommended.
Another important advantage is improved compatibility with the wider ecosystem. Since Zone.js patches browser APIs, it sometimes struggles to keep up with new APIs or modern JavaScript features like async/await, which require special handling. Eliminating Zone.js removes this layer of complexity, leading to better long-term maintainability and fewer compatibility headaches.
For in-depth details, migration advice, and performance insights, check out my full guide.
Vitest – New Default Testing Framework
Angular 21 introduces Vitest as the new standard testing framework, replacing Jasmine and Karma for newly created projects. This shift comes after years of uncertainty following Karma’s deprecation in 2023, providing Angular developers with a clear, modern, and efficient testing solution.
Key Benefits:
- Fast test runs powered by the Vite build tool
- Native support for TypeScript and ESM
- Real browser environment testing
- Modern and rich API
Angular’s move to Vitest means better alignment with the modern JS ecosystem, and future migration utilities will ease switching from Jasmine. Developers will run tests the same way with ng test. Importantly, Jasmine and Karma can still be chosen instead of Vitest if needed.

Figure 3: The Vitest test result in console
Angular ARIA
Angular ARIA is a library created in response to developer requests for accessible components that are simpler to style. It provides a collection of headless Angular directives implementing common accessibility patterns without any predefined styles, allowing developers full control over styling.
Currently, the Angular ARIA library includes accessible directives for the following UI components:
- Accordion
- Combobox
- Listbox
- Radio Group
- Tabs
- Toolbar
<div ngListbox>
@for (item of crew.value(); track item.id) {
<div [value]="item.name" ngOption>{{ item.name }}</div>
}
</div>

Figure 4: ARIA roles and attributes automatically added by using Angular ARIA directives
Other Improvements
Angular 21 goes beyond major new features by delivering various improvements, migrations, and quality enhancements that together modernize and optimize Angular apps.
- The HttpClient is built in by default, so new projects no longer require manual setup of provideHttpClient().
- Migration Scripts:
- Migration from NgClass to class bindings:
ng generate @angular/core:ngclass-to-class - Migration from NgStyle to style bindings:
ng generate @angular/core:ngstyle-to-style - Migration of RouterTestingModule usages inside tests to RouterModule:
ng generate @angular/core:router-testing-module-migration - Replacement of CommonModule imports with standalone imports:
ng generate @angular/core:common-to-standalone
- Migration from NgClass to class bindings:
- CLI support for Tailwind CSS config generation, making it easier to set up Tailwind CSS in Angular projects right from project creation.

Figure 5: CLI support for Tailwind CSS config generation
In addition to these changes, Angular 21 includes numerous bug fixes, performance improvements, and developer experience enhancements that make the framework more stable, efficient, and user-friendly.
Conclusion
Angular 21 delivers a thoughtful balance of innovation and refinement, introducing tools that make modern app development more efficient and enjoyable. Signal Forms, Vitest, default zoneless mode, and Angular ARIA directives all emphasize what this update is about: speed, clarity, and accessibility.
Angular continues to prove that a mature framework can still innovate, adapt, and surprise.
References
🔍 Frequently Asked Questions (FAQ)
1. What are Signal Forms in Angular 21?
Signal Forms in Angular 21 introduce a new, reactive way to manage form state using signals. This experimental feature allows developers to declaratively define forms that remain synchronized with their underlying signal-based model, enabling more efficient and readable form handling.
2. How do you bind fields in a Signal Form?
Angular 21 uses the Field directive for two-way binding between form inputs and signal-based models. Developers add [field] to input elements and map them to specific fields in the Signal Form, ensuring real-time updates between the view and data model.
3. How is validation implemented in Signal Forms?
Validation in Signal Forms is added via a schema function passed to the form() method. This function can include Angular’s built-in validators and custom messages, allowing for tailored and user-friendly error feedback displayed only after user interaction.
4. What is zoneless change detection in Angular 21?
Zoneless change detection is now enabled by default in Angular 21, removing the dependency on Zone.js.. Change detection no longer triggers on all async operations but instead activates explicitly, resulting in improved performance, cleaner stack traces, and smaller bundle sizes.
5. How does zoneless mode improve app performance?
By removing Zone.js, Angular avoids unnecessary change detection cycles and reduces overhead. Performance improves as detection is limited to explicit triggers such as markForCheck(), async pipes, or template-bound signal updates.
6. Why did Angular 21 switch to Vitest for testing?
Angular 21 adopts Vitest as the default testing framework for new projects. Vitest offers fast execution via Vite, native TypeScript and ESM support, and a modern API aligned with current JavaScript testing trends.
7. What is Angular ARIA and what components does it support?
Angular ARIA is a new library offering headless directives for accessible components without enforced styling. It currently supports Accordion, Combobox, Listbox, Radio Group, Tabs, and Toolbar, enhancing accessibility while preserving design flexibility.
8. What CLI migration tools are available in Angular 21?
Angular 21 includes CLI commands for migrating NgClass, NgStyle, and RouterTestingModule usage, and for replacing CommonModule with standalone imports. It also adds CLI support for generating Tailwind CSS configuration during project setup.
9. What are the benefits of removing Zone.js from Angular apps?
Removing Zone.js simplifies debugging, reduces bundle size, enhances compatibility with modern browser APIs, and improves Core Web Vitals. It also future-proofs Angular applications against changes in JavaScript runtime behavior.
10. What should developers consider when adopting Signal Forms?
As an experimental API, Signal Forms may evolve in syntax or behavior. Developers should refer to the latest Angular documentation and be cautious when using it in production, while leveraging its benefits for cleaner, reactive form logic.





6 months access to session recordings.