Sync material tabs with anchor/hash

By default `MatTabsGroup` opens the first available tab. We can change it via input, but a more elegant way is to create a logic to save the selected tab into a URL (thanks to the anchor) and allow users to send a URL with the already selected tab.

You can view the source code for this project by following this link: GitHub

Demo

To see how the anchor is changing during navigation through tabs open the demo in a new window.

Writing logic to sync a tab with an anchor

We can move all logic related to synchronizing the opened tab with hash to directive. Thanks of that our solution will be very easy to use in other places.

@Directive({
standalone: true,
selector: "[appSyncTabsWithAnchor]",
})
export class SyncTabsWithAnchor implements AfterContentInit {
private group = inject(MatTabGroup, { self: true });
private router = inject(Router);
private activatedRoute = inject(ActivatedRoute);
private destroyRef = inject(DestroyRef);
ngAfterContentInit() {
const fragment = this.activatedRoute.snapshot.fragment;
if (fragment) {
const indexByLabel = this.group._tabs.toArray().findIndex((tab) => tab.textLabel === fragment);
if (indexByLabel !== -1) {
this.group.selectedIndex = indexByLabel;
} else {
this.group.selectedIndex = +fragment.replace("tab-", "") || 0;
}
}
const tabChangeSub = this.group.selectedTabChange.subscribe((event) =>
this.router.navigate([], {
relativeTo: this.activatedRoute,
fragment: event.tab.textLabel || "tab-" + event.index.toString(),
replaceUrl: true,
}),
);
this.destroyRef.onDestroy(() => tabChangeSub.unsubscribe());
}
}

Take a look at how the directive works. First, the directive checks if a tab has label. If not the directive will create a fake ID with the pattern tab-{index}.

How to use

To use the directive just add the selector to a component.

<mat-tab-group appSyncTabsWithAnchor>
<mat-tab label="First"> Content 1 </mat-tab>
<mat-tab label="Second"> Content 2 </mat-tab>
<mat-tab label="Third"> Content 3 </mat-tab>
</mat-tab-group>

Do not forget to import the directive to your component/module.

You cannot have more than one mat-tab-group on the page. To get a deal with it you should rewrite logic to save the opened tab in another place (for example in query params).

Do you like the content?

Your support helps me continue my work. Please consider making a donation.

Donations are accepted through PayPal or Stripe. You do not need a account to donate. All major credit cards are accepted.

Portrait of the author

About me

A JavaScript specialist with many years of industry experience whose heart beats for Angular. A follower of the "Keep it simple, stupid" principle and a fan of clean code and good architecture. Fearless in the face of the toughest challenges, I always look for simple and effective solutions. As a pragmatist and an enthusiast of new technologies, I passionately follow the trends in the JavaScript world. After hours — a sailor who loves discovering new places and spending time on trips. My favorite motto? "Talk is cheap. Show me the code."

Leave a comment