@atom_design/tooltip
v1.0.0
Published
A customizable React Native tooltip component with smart positioning, animations, and rich content support.
Readme
@atom_design/tooltip
A highly customizable, accessible React Native Tooltip component with smart positioning, smooth animations, and support for rich content.
Features
- 📍 4 Positions: top, bottom, left, right
- 🎯 Smart Positioning: Auto-adjusts to stay within screen bounds
- 🎬 Smooth Animations: Fade in/out with customizable duration
- 📝 Rich Content: String, title+text, or custom components
- 🎨 Fully Customizable: Colors, sizes, styles
- ♿ Accessible: Full accessibility support
- 🎯 TypeScript: Full TypeScript definitions included
- 📱 Cross-Platform: Works on iOS and Android
Installation
npm install @atom_design/tooltip
# or
yarn add @atom_design/tooltipPeer Dependencies
npm install react react-native prop-typesUsage
Basic Usage
import Tooltip from '@atom_design/tooltip';
import { Text } from 'react-native';
<Tooltip content="Hello, I am a tooltip!">
<Text>ℹ️ Tap me</Text>
</Tooltip>Positions
<Tooltip content="Top tooltip" position="top">
<Text>Top</Text>
</Tooltip>
<Tooltip content="Bottom tooltip" position="bottom">
<Text>Bottom</Text>
</Tooltip>
<Tooltip content="Left tooltip" position="left">
<Text>Left</Text>
</Tooltip>
<Tooltip content="Right tooltip" position="right">
<Text>Right</Text>
</Tooltip>Rich Content (Title + Text)
<Tooltip
content={{
title: 'Popover Title',
text: 'This is the detailed description that appears below the title.',
}}
position="bottom"
>
<Text>ℹ️</Text>
</Tooltip>Custom Component Content
<Tooltip
content={{
title: 'Actions',
component: (
<View style={{ flexDirection: 'row', gap: 10, marginTop: 10 }}>
<Button title="Edit" onPress={() => {}} />
<Button title="Delete" onPress={() => {}} />
</View>
),
}}
>
<Text>⋮</Text>
</Tooltip>Custom Colors
// Dark tooltip
<Tooltip
content="Dark themed tooltip"
backgroundColor="#333"
textColor="#fff"
>
<Text>Dark</Text>
</Tooltip>
// Brand colored
<Tooltip
content="Brand tooltip"
backgroundColor="#d9232d"
textColor="#fff"
>
<Text>Brand</Text>
</Tooltip>Custom Styling
<Tooltip
content="Styled tooltip"
tooltipStyle={{
borderRadius: 12,
padding: 16,
borderWidth: 1,
borderColor: '#ddd',
}}
textStyle={{
fontSize: 16,
fontWeight: '500',
}}
>
<Text>Styled</Text>
</Tooltip>Without Arrow
<Tooltip content="No arrow" showArrow={false}>
<Text>No Arrow</Text>
</Tooltip>With Overlay
<Tooltip
content="Dimmed background"
overlayColor="rgba(0,0,0,0.3)"
>
<Text>With Overlay</Text>
</Tooltip>Callbacks
<Tooltip
content="Tracked tooltip"
onShow={() => console.log('Tooltip shown')}
onHide={() => console.log('Tooltip hidden')}
>
<Text>Tracked</Text>
</Tooltip>Disabled State
<Tooltip content="Won't show" disabled={true}>
<Text>Disabled</Text>
</Tooltip>Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| children | ReactNode | - | Trigger element (required) |
| content | string \| TooltipContent \| ReactNode | - | Tooltip content |
| position | 'top' \| 'bottom' \| 'left' \| 'right' | 'top' | Tooltip position |
| backgroundColor | string | '#fff' | Background color |
| textColor | string | '#333' | Text color |
| arrowSize | number | 6 | Arrow size in pixels |
| maxWidth | number | 250 | Maximum tooltip width |
| disabled | boolean | false | Disable tooltip |
| showArrow | boolean | true | Show/hide arrow |
| animationDuration | number | 200 | Animation duration (ms) |
| onShow | () => void | - | Callback when shown |
| onHide | () => void | - | Callback when hidden |
| containerStyle | StyleProp<ViewStyle> | - | Container style |
| tooltipStyle | StyleProp<ViewStyle> | - | Tooltip box style |
| textStyle | StyleProp<TextStyle> | - | Text style |
| titleStyle | StyleProp<TextStyle> | - | Title style |
| overlayColor | string | 'transparent' | Overlay background |
| closeOnOverlayPress | boolean | true | Close on overlay tap |
| testID | string | - | Test ID |
| accessibilityLabel | string | - | A11y label |
TooltipContent Interface
interface TooltipContent {
title?: string; // Bold title text
text?: string; // Body text
component?: ReactNode; // Custom component
}Accessibility
The Tooltip component is fully accessible:
- Uses
accessibilityRole="button"for trigger - Uses
accessibilityRole="tooltip"for content - Announces expanded state
- Provides interaction hints
- Uses
accessibilityLiveRegion="polite"for content
Full Test Screen Example
Copy this complete screen to test all tooltip variations in your app:
import React, { useState } from 'react';
import { ScrollView, View, Text, StyleSheet, Button } from 'react-native';
import Tooltip from '@atom_design/tooltip';
const TooltipTestScreen = () => {
const [showCount, setShowCount] = useState(0);
return (
<ScrollView style={styles.container} contentContainerStyle={styles.content}>
<Text style={styles.title}>@atom_design/tooltip</Text>
<Text style={styles.subtitle}>Complete Component Test</Text>
{/* POSITIONS SECTION */}
<Text style={styles.sectionTitle}>Positions</Text>
<View style={styles.positionsGrid}>
<View style={styles.positionRow}>
<Tooltip content="Tooltip on Top" position="top">
<View style={styles.trigger}>
<Text style={styles.triggerText}>Top</Text>
</View>
</Tooltip>
</View>
<View style={styles.positionRow}>
<Tooltip content="Tooltip on Left" position="left">
<View style={styles.trigger}>
<Text style={styles.triggerText}>Left</Text>
</View>
</Tooltip>
<View style={{ width: 60 }} />
<Tooltip content="Tooltip on Right" position="right">
<View style={styles.trigger}>
<Text style={styles.triggerText}>Right</Text>
</View>
</Tooltip>
</View>
<View style={styles.positionRow}>
<Tooltip content="Tooltip on Bottom" position="bottom">
<View style={styles.trigger}>
<Text style={styles.triggerText}>Bottom</Text>
</View>
</Tooltip>
</View>
</View>
{/* CONTENT TYPES SECTION */}
<Text style={styles.sectionTitle}>Content Types</Text>
<View style={styles.row}>
<Tooltip content="Simple text tooltip">
<View style={styles.iconTrigger}>
<Text style={styles.icon}>ℹ️</Text>
<Text style={styles.label}>Simple Text</Text>
</View>
</Tooltip>
<Tooltip
content={{
title: 'Popover Title',
text: 'This is the detailed description that provides more context.',
}}
>
<View style={styles.iconTrigger}>
<Text style={styles.icon}>📋</Text>
<Text style={styles.label}>Title + Text</Text>
</View>
</Tooltip>
</View>
<Text style={styles.label}>Long Text Content</Text>
<Tooltip
content="This is a much longer tooltip text that demonstrates how the tooltip handles wrapping and stays within screen boundaries. It should be easy to read and not overflow."
position="bottom"
>
<View style={styles.longTrigger}>
<Text>Tap to see long tooltip</Text>
</View>
</Tooltip>
<Text style={styles.label}>Custom Component</Text>
<Tooltip
content={{
title: 'Quick Actions',
component: (
<View style={styles.customContent}>
<Text style={styles.customAction}>✏️ Edit</Text>
<Text style={styles.customAction}>📋 Copy</Text>
<Text style={styles.customAction}>🗑️ Delete</Text>
</View>
),
}}
position="bottom"
maxWidth={180}
>
<View style={styles.longTrigger}>
<Text>⋮ More Actions</Text>
</View>
</Tooltip>
{/* COLORS SECTION */}
<Text style={styles.sectionTitle}>Custom Colors</Text>
<View style={styles.row}>
<Tooltip
content="Dark tooltip"
backgroundColor="#333"
textColor="#fff"
>
<View style={[styles.trigger, { backgroundColor: '#333' }]}>
<Text style={[styles.triggerText, { color: '#fff' }]}>Dark</Text>
</View>
</Tooltip>
<Tooltip
content="Brand tooltip"
backgroundColor="#d9232d"
textColor="#fff"
>
<View style={[styles.trigger, { backgroundColor: '#d9232d' }]}>
<Text style={[styles.triggerText, { color: '#fff' }]}>Brand</Text>
</View>
</Tooltip>
<Tooltip
content="Success tooltip"
backgroundColor="#34C759"
textColor="#fff"
>
<View style={[styles.trigger, { backgroundColor: '#34C759' }]}>
<Text style={[styles.triggerText, { color: '#fff' }]}>Success</Text>
</View>
</Tooltip>
</View>
<View style={styles.row}>
<Tooltip
content="Info tooltip"
backgroundColor="#007AFF"
textColor="#fff"
>
<View style={[styles.trigger, { backgroundColor: '#007AFF' }]}>
<Text style={[styles.triggerText, { color: '#fff' }]}>Info</Text>
</View>
</Tooltip>
<Tooltip
content="Warning tooltip"
backgroundColor="#FF9500"
textColor="#fff"
>
<View style={[styles.trigger, { backgroundColor: '#FF9500' }]}>
<Text style={[styles.triggerText, { color: '#fff' }]}>Warning</Text>
</View>
</Tooltip>
</View>
{/* STYLING SECTION */}
<Text style={styles.sectionTitle}>Styling Options</Text>
<View style={styles.row}>
<Tooltip content="No arrow pointer" showArrow={false}>
<View style={styles.trigger}>
<Text style={styles.triggerText}>No Arrow</Text>
</View>
</Tooltip>
<Tooltip content="Large arrow" arrowSize={10}>
<View style={styles.trigger}>
<Text style={styles.triggerText}>Big Arrow</Text>
</View>
</Tooltip>
</View>
<View style={styles.row}>
<Tooltip
content="With overlay background"
overlayColor="rgba(0,0,0,0.3)"
>
<View style={styles.trigger}>
<Text style={styles.triggerText}>Overlay</Text>
</View>
</Tooltip>
<Tooltip
content="Custom styled tooltip"
tooltipStyle={{
borderRadius: 16,
borderWidth: 2,
borderColor: '#d9232d',
}}
textStyle={{
fontWeight: 'bold',
color: '#d9232d',
}}
>
<View style={styles.trigger}>
<Text style={styles.triggerText}>Styled</Text>
</View>
</Tooltip>
</View>
{/* CALLBACKS SECTION */}
<Text style={styles.sectionTitle}>Callbacks</Text>
<Text style={styles.info}>Tooltip shown: {showCount} times</Text>
<Tooltip
content="This tooltip tracks when it's shown"
onShow={() => setShowCount(prev => prev + 1)}
onHide={() => console.log('Hidden')}
>
<View style={styles.longTrigger}>
<Text>Tap to increment counter</Text>
</View>
</Tooltip>
{/* STATES SECTION */}
<Text style={styles.sectionTitle}>States</Text>
<View style={styles.row}>
<Tooltip content="Normal tooltip">
<View style={styles.trigger}>
<Text style={styles.triggerText}>Normal</Text>
</View>
</Tooltip>
<Tooltip content="Won't show" disabled={true}>
<View style={[styles.trigger, styles.disabledTrigger]}>
<Text style={[styles.triggerText, { color: '#999' }]}>Disabled</Text>
</View>
</Tooltip>
</View>
{/* EDGE CASES SECTION */}
<Text style={styles.sectionTitle}>Edge Cases</Text>
<Text style={styles.label}>Near Screen Edge (Left)</Text>
<View style={{ alignItems: 'flex-start' }}>
<Tooltip content="This tooltip adjusts to stay on screen" position="top">
<View style={styles.trigger}>
<Text style={styles.triggerText}>Edge</Text>
</View>
</Tooltip>
</View>
<Text style={styles.label}>Near Screen Edge (Right)</Text>
<View style={{ alignItems: 'flex-end' }}>
<Tooltip content="This tooltip adjusts to stay on screen" position="top">
<View style={styles.trigger}>
<Text style={styles.triggerText}>Edge</Text>
</View>
</Tooltip>
</View>
<View style={{ height: 100 }} />
</ScrollView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f5f5f5',
},
content: {
padding: 20,
},
title: {
fontSize: 28,
fontWeight: 'bold',
textAlign: 'center',
marginBottom: 5,
color: '#333',
},
subtitle: {
fontSize: 16,
textAlign: 'center',
marginBottom: 30,
color: '#666',
},
sectionTitle: {
fontSize: 18,
fontWeight: '600',
marginTop: 30,
marginBottom: 15,
color: '#333',
borderBottomWidth: 1,
borderBottomColor: '#ddd',
paddingBottom: 5,
},
label: {
fontSize: 14,
color: '#666',
marginBottom: 8,
marginTop: 15,
},
info: {
fontSize: 14,
color: '#666',
marginBottom: 10,
fontFamily: 'monospace',
},
row: {
flexDirection: 'row',
flexWrap: 'wrap',
gap: 15,
marginBottom: 10,
},
positionsGrid: {
alignItems: 'center',
gap: 20,
paddingVertical: 20,
},
positionRow: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
trigger: {
backgroundColor: '#e0e0e0',
paddingVertical: 10,
paddingHorizontal: 16,
borderRadius: 8,
alignItems: 'center',
justifyContent: 'center',
},
triggerText: {
fontSize: 14,
fontWeight: '600',
color: '#333',
},
iconTrigger: {
alignItems: 'center',
gap: 5,
},
icon: {
fontSize: 30,
},
longTrigger: {
backgroundColor: '#e0e0e0',
padding: 16,
borderRadius: 8,
alignItems: 'center',
},
disabledTrigger: {
backgroundColor: '#f0f0f0',
opacity: 0.6,
},
customContent: {
marginTop: 10,
gap: 8,
},
customAction: {
fontSize: 14,
paddingVertical: 4,
},
});
export default TooltipTestScreen;Usage in Your App
// App.js or navigation screen
import TooltipTestScreen from './TooltipTestScreen';
// In your navigator or directly
<TooltipTestScreen />License
MIT © Atom Design
