Tooltips are the silent helpers of modern UIs, revealing information without cluttering the screen. In Angular 16, the Angular Material library already offers a robust Angular Material Tooltip directive, but when you need a reusable component that supports custom themes and fits into a design system, you must build it yourself.
Why Reusable Angular Material Tooltips Matter
Reusing a single, well‑tested component saves developers time, maintains consistency, and makes theming trivial. Rather than sprinkling matTooltip on every element, a wrapper lets you control style, positioning, and accessibility in one place.
Step 1: Setting Up the Angular 16 Project
Create a fresh workspace and add Angular Material:
ng new tooltip-demo– select CSS or SCSS.cd tooltip-demong add @angular/material– choose a pre‑built theme.- Install Storybook:
npx sb init --builder @storybook/angular.
These commands yield a clean slate with Material styles and Storybook scaffolding ready.
Step 2: Creating the Tooltip Component
Template
Create src/app/tooltip/tooltip.component.html:
<span matTooltip="{{tooltipText}}" matTooltipPosition="{{position}}" class="tooltip-trigger">
<ng-content></ng-content>
</span>
Component Class
In tooltip.component.ts, expose inputs for text, position, and theme:
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-tooltip',
templateUrl: './tooltip.component.html',
styleUrls: ['./tooltip.component.scss']
})
export class TooltipComponent {
@Input() tooltipText = 'Tooltip';
@Input() position: 'above' | 'below' | 'left' | 'right' = 'above';
@Input() theme: string = 'default';
}
Styles
Use CSS variables for theming in tooltip.component.scss:
:host {
--tooltip-bg: #{$tooltipBg};
--tooltip-color: #{$tooltipColor};
}
.tooltip-trigger::ng-deep .mat-tooltip {
background-color: var(--tooltip-bg);
color: var(--tooltip-color);
}
Replace $tooltipBg and $tooltipColor with theme values injected at runtime.
Step 3: Implementing Custom Theme Support
Theme Service
Create a simple service that exposes current theme variables:
import { Injectable } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class TooltipThemeService {
private themes = {
default: { bg: '#333', color: '#fff' },
blue: { bg: '#1976d2', color: '#fff' },
dark: { bg: '#222', color: '#ddd' }
};
getTheme(themeName: string) {
return this.themes[themeName] ?? this.themes.default;
}
}
Injecting Variables
In the component, update host styles whenever the theme changes:
import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
export class TooltipComponent implements OnChanges {
// previous inputs …
constructor(private themeService: TooltipThemeService) {}
ngOnChanges(changes: SimpleChanges) {
const theme = this.themeService.getTheme(this.theme);
document.documentElement.style.setProperty('--tooltipBg', theme.bg);
document.documentElement.style.setProperty('--tooltipColor', theme.color);
}
}
Step 4: Registering the Component
Create a module tooltip.module.ts:
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatTooltipModule } from '@angular/material/tooltip';
import { TooltipComponent } from './tooltip.component';
@NgModule({
declarations: [TooltipComponent],
imports: [CommonModule, MatTooltipModule],
exports: [TooltipComponent]
})
export class TooltipModule {}
Import TooltipModule into your app module or feature modules.
Step 5: Storybook Integration for Design System
Storybook Configuration
Update .storybook/main.js to include Angular Material and SCSS support:
module.exports = {
stories: ['../src/**/*.stories.@(js|ts|mdx)'],
framework: '@storybook/angular',
webpackFinal: async (config) => {
config.module.rules.push({
test: /.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader']
});
return config;
}
};
Tooltip Story
Create src/app/tooltip/tooltip.stories.ts:
import { moduleMetadata } from '@storybook/angular';
import { TooltipComponent } from './tooltip.component';
import { TooltipModule } from './tooltip.module';
export default {
title: 'Components/Tooltip',
component: TooltipComponent,
decorators: [
moduleMetadata({
imports: [TooltipModule]
})
]
};
const Template = (args: TooltipComponent) => ({
props: args,
template: ``
});
export const Default = Template.bind({});
Default.args = {
tooltipText: 'This is a reusable tooltip',
position: 'below',
theme: 'default'
};
Theming in Storybook
To showcase the blue variant, add another story:
export const Blue = Template.bind({});
Blue.args = {
...Default.args,
theme: 'blue'
};
Your Storybook now displays the component with multiple themes, making it a living documentation asset.
Demo and Usage Example
Use the component inside any template:
<app-tooltip tooltipText="Edit this item" position="right" theme="dark">
<mat-icon>edit</mat-icon>
</app-tooltip>
All styling, positioning, and theming logic is encapsulated, so developers can drop the wrapper wherever needed.
Testing & Accessibility Tips
Angular Material already handles ARIA attributes, but keep an eye on:
- Focus visibility – ensure tooltips appear on keyboard navigation.
- Use
routerLinkelements inside the trigger so the link text is still discernible. - Run
ng testwithjasmine --save-changesto verify content renders correctly for each theme.
Conclusion
By encapsulating matTooltip into a small, theme‑aware component you achieve consistency, improve maintainability, and provide a single source of truth for tooltip styling. Export the component, document it in Storybook, and reuse it across your application with confidence.
Ready to boost your design system? Start by cloning this repo and experimenting with a new theme – the possibilities are endless.