Create a Reusable Angular Material Tooltip with Custom Themes & Storybook in Angular 16

User avatar placeholder
Written by Tamzid Ahmed

August 20, 2026

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:

  1. ng new tooltip-demo – select CSS or SCSS.
  2. cd tooltip-demo
  3. ng add @angular/material – choose a pre‑built theme.
  4. 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 routerLink elements inside the trigger so the link text is still discernible.
  • Run ng test with jasmine --save-changes to 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.

Leave a Comment