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.