Skip to content

Pending Review

Pending Review from User Experience (UX)

Tooltip Component

Overview

The PWC Tooltip component provides contextual information and helpful hints that appear on hover or focus interactions. Built on Lit web components with Floating UI positioning, it offers precise placement, automatic collision detection, and accessibility features to enhance user understanding without cluttering the interface.

Core Capabilities

  • Dynamic Positioning - Intelligent placement with automatic flip and shift when constrained by viewport boundaries
  • Multiple Positions - Four directional options (top, right, bottom, left) with automatic collision avoidance
  • Flexible Content - Support for both simple text tooltips and structured content with headings
  • Interaction Triggers - Mouse hover and keyboard focus events for comprehensive accessibility support
  • Arrow Indicators - Visual arrows that point to the anchor element for clear association
  • Floating UI Integration - Advanced positioning system with offset, flip, shift, and arrow middleware

When to use Tooltip:

  • Contextual Help - Provide additional information about interface elements without navigating away
  • Icon Explanations - Clarify the purpose of icons, buttons, and interactive elements
  • Form Assistance - Offer input guidance and validation hints for form fields and controls
  • Feature Discovery - Help users understand new features and functionality through progressive disclosure

When not to use Tooltip:

  • Essential Information - Don't hide critical information that users need to complete tasks
  • Mobile Interfaces - Avoid tooltips on touch devices where hover interactions aren't reliable
  • Complex Content - Use dedicated modals or panels for lengthy explanations and rich content

Basic Implementation

import React, { useState, useRef, useCallback } from 'react';
import { PwcButton, PwcIcon } from '@progress-i360/pwc-react';
import { renderTooltip } from '@progress-i360/pwc-react/tooltip';

function HelpSystem() {
  const [tooltipPosition, setTooltipPosition] = useState('top');
  const [showAdvanced, setShowAdvanced] = useState(false);
  const buttonRef = useRef(null);
  const iconRef = useRef(null);

  // React 18: useCallback for optimization
  const cyclePosition = useCallback(() => {
    const positions = ['top', 'right', 'bottom', 'left'];
    const currentIndex = positions.indexOf(tooltipPosition);
    setTooltipPosition(positions[(currentIndex + 1) % positions.length]);
  }, [tooltipPosition]);

  const toggleAdvanced = useCallback(() => {
    setShowAdvanced(prev => !prev);
  }, []);

  return (
      <div style={{ padding: '40px', textAlign: 'center' }}>
        <div style={{ marginBottom: '20px' }}>
          <PwcButton 
            ref={buttonRef}
            label="Save Document"
            variant="primary"
          />
          {renderTooltip({
            anchor: buttonRef.current,
            heading: showAdvanced ? 'Save Options' : 'Quick Save',
            tooltip: showAdvanced ? 
              'Saves to current location with backup creation' : 
              'Save your document',
            position: tooltipPosition
          })}
        </div>

        <div style={{ marginBottom: '20px' }}>
          <PwcIcon 
            ref={iconRef}
            iconKey="help"
            size="l"
            color="info"
            clickable
          />
          {renderTooltip({
            anchor: iconRef.current,
            tooltip: 'Click for additional help resources',
            position: 'bottom'
          })}
        </div>

        <div style={{ display: 'flex', gap: '8px', justifyContent: 'center' }}>
          <PwcButton
            label={`Position: ${tooltipPosition}`}
            variant="outline"
            onPwcClick={cyclePosition}
          />
          <PwcButton
            label={showAdvanced ? 'Simple Mode' : 'Advanced Mode'}
            variant="outline"
            onPwcClick={toggleAdvanced}
          />
        </div>
      </div>
  );
}
import { Suspense, startTransition, use, useMemo, useState } from 'react';
import '@progress-i360/progress-web-components/tooltip';
import '@progress-i360/progress-web-components/button';
import '@progress-i360/progress-web-components/icon';

type TooltipMode = 'basic' | 'advanced';

const fetchTooltipContent = async (mode: TooltipMode) => {
  await new Promise(resolve => setTimeout(resolve, 100));
  if (mode === 'advanced') {
    return {
      heading: 'Advanced Features',
      tooltip: 'Unlock premium capabilities with detailed analytics and forecasting.'
    };
  }
  return {
    heading: 'Quick Action',
    tooltip: 'Execute with one-click simplicity and default settings.'
  };
};

function TooltipContent({ anchorId, promise }: { anchorId: string; promise: Promise<{ heading: string; tooltip: string }>; }) {
  const content = use(promise);
  return (
    <pwc-tooltip
      anchor={anchorId}
      heading={content.heading}
      tooltip={content.tooltip}
      position="bottom"
    ></pwc-tooltip>
  );
}

function IntelligentTooltips() {
  const [mode, setMode] = useState<TooltipMode>('basic');
  const [contentPromise, setContentPromise] = useState(() => fetchTooltipContent('basic'));

  const modeLabels = useMemo(() => ({
    basic: 'Basic Mode',
    advanced: 'Advanced Mode'
  }), []);

  const updateTooltipContent = (nextMode: TooltipMode) => {
    startTransition(() => {
      setMode(nextMode);
      setContentPromise(fetchTooltipContent(nextMode));
    });
  };

  return (
      <div style={{ padding: '40px', textAlign: 'center' }}>
        <div style={{ marginBottom: '20px' }}>
          <pwc-button id="smart-action" label="Smart Action" variant="primary"></pwc-button>
          <pwc-tooltip
            anchor="smart-action"
            heading="Context-Aware Help"
            tooltip="This tooltip adapts based on your current workflow."
            position="top"
          ></pwc-tooltip>
        </div>

        <div style={{ marginBottom: '20px' }}>
          <pwc-button id="dynamic-tooltip" label="Dynamic Content" variant="secondary"></pwc-button>
          <Suspense fallback={
            <pwc-tooltip
              anchor="dynamic-tooltip"
              tooltip="Loading enhanced content..."
              position="bottom"
            ></pwc-tooltip>
          }>
            <TooltipContent anchorId="dynamic-tooltip" promise={contentPromise} />
          </Suspense>
        </div>

        <div style={{ display: 'flex', gap: '8px', justifyContent: 'center' }}>
          <pwc-button
            label={modeLabels.basic}
            variant={mode === 'basic' ? 'primary' : 'outline'}
            onPwcClick={() => updateTooltipContent('basic')}
          ></pwc-button>
          <pwc-button
            label={modeLabels.advanced}
            variant={mode === 'advanced' ? 'primary' : 'outline'}
            onPwcClick={() => updateTooltipContent('advanced')}
          ></pwc-button>
        </div>
      </div>
  );
}
import { Component, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
import "@progress-i360/progress-web-components/tooltip";
import "@progress-i360/progress-web-components/button";
import "@progress-i360/progress-web-components/icon";
import "@progress-i360/progress-web-components/flex";
import "@progress-i360/progress-web-components/heading";

@Component({
  selector: 'tooltip-demo',
  template: `
    <pwc-flex direction="column" gap="m" padding="m" align-items="flex-start">
      <pwc-heading content="Tooltip Examples" size="l"></pwc-heading>

      <pwc-button id="save-action" label="Save" variant="primary"></pwc-button>
      <pwc-tooltip
        anchor="save-action"
        heading="Save Document"
        [tooltip]="'Creates a new version and preserves your changes.'"
        [position]="tooltipPosition">
      </pwc-tooltip>

      <pwc-flex gap="s" align-items="center">
        <pwc-icon id="help-icon" iconKey="information" color="info"></pwc-icon>
        <pwc-tooltip
          anchor="help-icon"
          [tooltip]="mode === 'advanced' ? advancedHint : basicHint"
          position="bottom">
        </pwc-tooltip>
      </pwc-flex>

      <pwc-flex gap="s">
        <pwc-button label="Rotate Position" variant="outline" (pwc-click)="rotatePosition()"></pwc-button>
        <pwc-button label="Toggle Mode" variant="outline" (pwc-click)="toggleMode()"></pwc-button>
      </pwc-flex>
    </pwc-flex>
  `,
  schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class TooltipDemo {
  tooltipPosition: 'top' | 'right' | 'bottom' | 'left' = 'right';
  mode: 'basic' | 'advanced' = 'basic';
  basicHint = 'Opens contextual help for this feature.';
  advancedHint = 'Provides deep-dive resources tailored to advanced workflows.';

  private readonly positions: Array<'top' | 'right' | 'bottom' | 'left'> = ['right', 'bottom', 'left', 'top'];

  rotatePosition() {
    const index = this.positions.indexOf(this.tooltipPosition);
    this.tooltipPosition = this.positions[(index + 1) % this.positions.length];
  }

  toggleMode() {
    this.mode = this.mode === 'basic' ? 'advanced' : 'basic';
  }
}
import '@progress-i360/progress-web-components/tooltip';
import '@progress-i360/progress-web-components/button';

const container = document.createElement('div');
container.style.display = 'flex';
container.style.gap = '2rem';
container.style.padding = '2rem';
container.style.justifyContent = 'center';

const infoButton = document.createElement('pwc-button');
infoButton.setAttribute('id', 'info-button');
infoButton.setAttribute('label', 'Hover Me');
infoButton.setAttribute('variant', 'primary');

const infoTooltip = document.createElement('pwc-tooltip');
infoTooltip.setAttribute('anchor', 'info-button');
infoTooltip.setAttribute('heading', 'Quick Tip');
infoTooltip.setAttribute('tooltip', 'Tooltips provide short, contextual guidance.');
infoTooltip.setAttribute('position', 'top');

const clickButton = document.createElement('pwc-button');
clickButton.setAttribute('id', 'click-button');
clickButton.setAttribute('label', 'Click Me');
clickButton.setAttribute('variant', 'outline');

const clickTooltip = document.createElement('pwc-tooltip');
clickTooltip.setAttribute('anchor', 'click-button');
clickTooltip.setAttribute('tooltip', 'This tooltip toggles on click.');
clickTooltip.setAttribute('position', 'right');
clickTooltip.setAttribute('trigger', 'click');

clickTooltip.addEventListener('pwc-toggle', (event) => {
  console.log('Tooltip visibility changed:', event.detail?.open);
});

container.appendChild(infoButton);
container.appendChild(clickButton);
container.appendChild(infoTooltip);
container.appendChild(clickTooltip);
document.body.appendChild(container);

Usage Patterns

Positioning Configuration

Flexible tooltip placement using Floating UI:

// Auto-positioning with fallbacks
<pwc-tooltip position="top" fallback={['bottom', 'left', 'right']}>

// Fixed positioning
<pwc-tooltip position="bottom-start">

// Dynamic positioning with collision detection  
<pwc-tooltip position="auto" boundary="viewport">

Trigger Methods

Multiple activation patterns:

// Hover trigger (default)
<pwc-tooltip trigger="hover">

// Focus trigger for accessibility
<pwc-tooltip trigger="focus">

// Manual control
<pwc-tooltip trigger="manual" open={isVisible}>

Content Variations

Flexible content display:

// Simple text tooltip
<pwc-tooltip content="Save your work">

// Structured content
<pwc-tooltip heading="Save Options" content="Choose location">

// Rich HTML content
<pwc-tooltip>
  <div slot="content">
    <strong>Pro Tip:</strong> Use Ctrl+S
  </div>
</pwc-tooltip>

Best Practices

Content Guidelines

  • Keep it Brief - Use concise, helpful text that enhances understanding
  • Provide Value - Include information that helps users complete tasks
  • Stay Relevant - Ensure tooltip content directly relates to the trigger element
  • Use Plain Language - Avoid jargon and technical terms when possible

Positioning Strategy

  • Use Auto-positioning - Let Floating UI handle optimal placement
  • Consider Viewport - Ensure tooltips stay within visible boundaries
  • Account for Scrolling - Position tooltips relative to stable elements
  • Test Edge Cases - Verify behavior at viewport edges and corners

Performance Optimization

  • Lazy Loading - Initialize tooltips only when needed
  • Event Cleanup - Properly dispose of event listeners
  • Debounce Events - Prevent excessive tooltip updates
  • Minimal DOM - Keep tooltip content lightweight

Accessibility Focus

  • Keyboard Support - Ensure tooltips work with keyboard navigation
  • Screen Readers - Use proper ARIA attributes for assistive technology
  • Focus Management - Don't trap focus within tooltips
  • Timing Control - Allow users to control tooltip display duration

Common Use Cases

Button Clarification

Explain icon buttons and complex controls: - Save, edit, delete action confirmations - Settings and configuration option descriptions - Navigation destination previews

Form Assistance

Provide contextual help for form inputs: - Field format requirements and examples
- Validation error explanations - Input value suggestions and constraints

Data Enhancement

Display additional information for data elements: - Truncated text full content expansion - Chart data point details and context - Table cell supplementary information

Feature Guidance

Support user learning and onboarding: - New feature announcements and explanations - Keyboard shortcut reminders - Process step clarifications and next actions

Troubleshooting

Display Issues

Tooltip Not Appearing

Symptoms: No tooltip shows on hover or focus

Solutions:

  • Verify anchor element exists in DOM
  • Check trigger event configuration
  • Ensure z-index layering is correct

Positioning Problems

Symptoms: Tooltip appears off-screen or in wrong location

Solutions:

  • Enable auto-positioning with Floating UI
  • Set proper boundary constraints
  • Check for CSS overflow hidden on parent elements

Content Issues

Symptoms: Text gets cut off or wraps poorly

Solutions:

  • Set appropriate max-width constraints
  • Use CSS text wrapping properties
  • Consider shorter content for better UX

Performance Issues

Memory Leaks

Symptoms: Browser performance degrades over time

Solutions:

  • Properly dispose of tooltip instances
  • Clean up event listeners on component unmount
  • Use weak references for large datasets

Rendering Delays

Symptoms: Tooltip appears slowly or with lag

Solutions:

  • Optimize content rendering
  • Use CSS transforms for positioning
  • Implement proper caching strategies

Implementation Support

Technical Assistance

For implementation questions and technical guidance:

  • Architecture Review - Component integration and performance optimization

  • Code Examples - Framework-specific implementation patterns

  • Testing Support - Unit testing strategies and accessibility validation

Integration Help

  • Framework Setup - React, Angular, and vanilla JavaScript configuration
  • Build Integration - Webpack, Vite, and other build tool setup
  • Performance Tuning - Optimization strategies for large-scale applications

Resources

Storybook Documentation

For comprehensive API documentation, interactive examples, and testing tools: 📖 View Complete API Documentation in Storybook →


This guide provides high-level implementation guidance. For detailed API specifications and interactive examples, visit our Storybook documentation.