InputModality

Signal-based wrapper around Angular CDK's InputModalityDetector. Reactively track the user's current input method (keyboard, mouse, or touch).

Recommended: Use Core Package

If you're not using @angular/cdk in your project, we recommend using inputModality from @signality/core instead. It provides the same functionality without requiring the CDK dependency:

typescript
import { inputModality } from '@signality/core'; 
import { inputModality } from '@signality/cdk-interop'; 

See InputModality from core for more details.

CDK Interop Package Required

This utility requires the @signality/cdk-interop and @angular/cdk packages to be installed:

bash
npm install @signality/cdk-interop @angular/cdk

Usage

angular-ts
import { Component, computed } from '@angular/core';
import { inputModality } from '@signality/cdk-interop';

@Component({
  template: `
    <div [class]="'input-mode-' + modality()">
      <p>Current input: {{ modality() ?? 'none' }}</p>
      <p>Using keyboard: {{ isKeyboard() }}</p>
    </div>
  `,
})
export class InputDemo {
  readonly modality = inputModality(); 
  readonly isKeyboard = computed(() => this.modality() === 'keyboard');
}

Parameters

ParameterTypeDescription
optionsInputModalityOptionsOptional configuration (see Options below)

Options

The InputModalityOptions extends CreateSignalOptions<InputModality> and WithInjector:

OptionTypeDescription
equalValueEqualityFn<InputModality>Custom equality function (see more)
debugNamestringDebug name for the signal (development only)
injectorInjectorOptional injector for DI context

Return Value

Returns a Signal<InputModality> containing the current input modality: 'keyboard', 'mouse', 'touch', or null.

Examples

Touch-optimized UI

angular-ts
import { Component, computed } from '@angular/core';
import { inputModality } from '@signality/cdk-interop';

@Component({
  template: `
    <nav [class.touch-mode]="isTouch()">
      <button [style.padding]="buttonPadding()">Menu</button>
      <button [style.padding]="buttonPadding()">Settings</button>
    </nav>
  `,
})
export class AdaptiveNav {
  readonly modality = inputModality();
  readonly isTouch = computed(() => this.modality() === 'touch');
  
  // Larger touch targets for touch input
  readonly buttonPadding = computed(() => 
    this.isTouch() ? '1rem 2rem' : '0.5rem 1rem'
  );
}

Analytics tracking

angular-ts
import { Component, effect, inject } from '@angular/core';
import { inputModality } from '@signality/cdk-interop';
import { AnalyticsService } from './analytics.service';

@Component({ /* ... */ })
export class AppComponent {
  readonly analytics = inject(AnalyticsService);
  readonly modality = inputModality();
  
  constructor() {
    effect(() => {
      const current = this.modality();
      if (current) {
        this.analytics.setUserProperty('input_modality', current); 
      }
    });
  }
}

Conditional tooltips

angular-ts
import { Component, computed } from '@angular/core';
import { inputModality } from '@signality/cdk-interop';

@Component({
  template: `
    <button 
      [attr.title]="showTooltip() ? 'Click to save' : null"
    >
      💾
    </button>
  `,
})
export class SaveButton {
  readonly modality = inputModality();
  
  // Only show native tooltips for mouse users
  readonly showTooltip = computed(() => this.modality() === 'mouse'); 
}

Type Definitions

typescript
type InputModalityOptions = CreateSignalOptions<InputModality> & WithInjector;

function inputModality(options?: InputModalityOptions): Signal<InputModality>;
Edit this page on GitHub Last updated: Mar 19, 2026, 23:28:23