@patternfly/react-core
Version:
This library provides a set of common React components for use with the PatternFly reference implementation.
322 lines (299 loc) • 11.3 kB
Markdown
---
id: Tooltip
section: components
cssPrefix: pf-c-tooltip
propComponents: ['Tooltip']
---
import OutlinedQuestionCircleIcon from '@patternfly/react-icons/dist/esm/icons/outlined-question-circle-icon';
import CopyIcon from '@patternfly/react-icons/dist/esm/icons/copy-icon';
import './TooltipExamples.css';
```js
import React from 'react';
import { Tooltip } from '@patternfly/react-core';
<div style={{ margin: '100px' }}>
<Tooltip
content={
<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam id feugiat augue, nec fringilla turpis.</div>
}
>
<span tabIndex="0" style={{ border: '1px dashed' }}>
I have a tooltip!
</span>
</Tooltip>
</div>;
```
```js
import React from 'react';
import { Tooltip } from '@patternfly/react-core';
TooltipReactRef = () => {
const tooltipRef = React.useRef();
return (
<div style={{ margin: '100px' }}>
<button aria-describedby="tooltip-ref1" ref={tooltipRef}>
Tooltip attached via react ref
</button>
<Tooltip
id="tooltip-ref1"
content={
<div>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam id feugiat augue, nec fringilla turpis.
</div>
}
reference={tooltipRef}
/>
</div>
);
};
```
```js
import React from 'react';
import { Tooltip } from '@patternfly/react-core';
<div style={{ margin: '100px' }}>
<button aria-describedby="tooltip-ref2" id="tooltip-selector">
Tooltip attached via selector ref
</button>
<Tooltip
id="tooltip-ref2"
content={
<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam id feugiat augue, nec fringilla turpis.</div>
}
reference={() => document.getElementById('tooltip-selector')}
/>
</div>;
```
When the tooltip is used as a wrapper and its content will dynamically update, the `aria` prop should have a value of "none" passed in. This prevents assistive technologies from announcing the tooltip contents more than once. Additionally, the `aria-live` prop should have a value of "polite" passed in, in order for assistive technologies to announce when the tooltip contents gets updated.
When using a React or selector ref with a tooltip that has dynamic content, the `aria` and `aria-live` props do not need to be manually passed in.
```js
import React from 'react';
import { Tooltip, Button } from '@patternfly/react-core';
import CopyIcon from '@patternfly/react-icons/dist/esm/icons/copy-icon';
IconExample = () => {
const [showSuccessContent, setShowSuccessContent] = React.useState(false);
const copyText = 'Copy to clipboard';
const doneCopyText = 'Successfully copied to clipboard!';
const [content, setContent] = React.useState(copyText);
return (
<div style={{ margin: '100px' }}>
<Tooltip aria="none" aria-live="polite" content={showSuccessContent ? doneCopyText : copyText}>
<Button
aria-label="Clipboard"
variant="plain"
id="tt-ref"
onClick={() => setShowSuccessContent(!showSuccessContent)}
>
<CopyIcon />
</Button>
</Tooltip>
</div>
);
};
```
```js
import React from 'react';
import { Button, Tooltip, Checkbox, Select, SelectOption, TextInput } from '@patternfly/react-core';
OptionsTooltip = () => {
const [trigger, setTrigger] = React.useState(['mouseenter', 'focus']);
const [isVisible, setIsVisible] = React.useState(true);
const [contentLeftAligned, setContentLeftAligned] = React.useState(false);
const [enableFlip, setEnableFlip] = React.useState(true);
const [position, setPosition] = React.useState('top');
const [positionSelectOpen, setPositionSelectOpen] = React.useState(false);
const [flipSelectOpen, setFlipSelectOpen] = React.useState(false);
const [flipBehavior, setFlipBehavior] = React.useState('flip');
const [entryDelayInput, setEntryDelayInput] = React.useState(0);
const [exitDelayInput, setExitDelayInput] = React.useState(0);
const [animationDuration, setAnimationDuration] = React.useState(300);
const tipBoxRef = React.useRef(null);
const scrollToRef = ref => {
if (ref && ref.current) {
ref.current.scrollTop = 400;
ref.current.scrollLeft = 300;
}
};
React.useEffect(() => {
scrollToRef(tipBoxRef);
}, []);
return (
<>
<div>
<div style={{ border: '1px solid' }}>
<Checkbox
label="trigger: mouseenter"
isChecked={trigger.includes('mouseenter')}
onChange={checked => {
let updatedTrigger;
checked && (updatedTrigger = trigger.concat('mouseenter'));
!checked && (updatedTrigger = trigger.filter(t => t !== 'mouseenter'));
setIsVisible(false);
setTrigger(updatedTrigger);
}}
aria-label="trigger: mouseenter"
id="trigger_mouseenter"
/>
<Checkbox
label="trigger: focus"
isChecked={trigger.includes('focus')}
onChange={checked => {
let updatedTrigger;
checked && (updatedTrigger = trigger.concat('focus'));
!checked && (updatedTrigger = trigger.filter(t => t !== 'focus'));
setIsVisible(false);
setTrigger(updatedTrigger);
}}
aria-label="trigger: focus"
id="trigger_focus"
/>
<Checkbox
label="trigger: click"
isChecked={trigger.includes('click')}
onChange={checked => {
let updatedTrigger;
checked && (updatedTrigger = trigger.concat('click'));
!checked && (updatedTrigger = trigger.filter(t => t !== 'click'));
setIsVisible(false);
setTimeout(() => setTrigger(updatedTrigger));
}}
aria-label="trigger: click"
id="trigger_click"
/>
<Checkbox
label="trigger: manual"
isChecked={trigger.includes('manual')}
onChange={checked => {
let updatedTrigger;
checked && (updatedTrigger = trigger.concat('manual'));
!checked && (updatedTrigger = trigger.filter(t => t !== 'manual'));
setIsVisible(false);
setTrigger(updatedTrigger);
}}
aria-label="trigger: manual"
id="trigger_manual"
/>
</div>
<div style={{ border: '1px solid' }}>
<Checkbox
label="content left-aligned"
isChecked={contentLeftAligned}
onChange={checked => setContentLeftAligned(checked)}
aria-label="content left-aligned"
id="content_left_aligned"
/>
</div>
<div style={{ border: '1px solid' }}>
<Checkbox
label="enableFlip"
isChecked={enableFlip}
onChange={checked => setEnableFlip(checked)}
aria-label="enableFlip"
id="enable_flip"
/>
</div>
<div style={{ border: '1px solid' }}>
position (will flip if enableFlip is true). The 'auto' position requires enableFlip to be set to true.
<Select
onToggle={() => setPositionSelectOpen(!positionSelectOpen)}
onSelect={(event, selection) => {
setPosition(selection);
setPositionSelectOpen(false);
}}
isOpen={positionSelectOpen}
selections={position}
menuAppendTo={() => document.body}
>
<SelectOption value="auto" />
<SelectOption value="top" />
<SelectOption value="bottom" />
<SelectOption value="left" />
<SelectOption value="right" />
<SelectOption value="top-start" />
<SelectOption value="top-end" />
<SelectOption value="bottom-start" />
<SelectOption value="bottom-end" />
<SelectOption value="left-start" />
<SelectOption value="left-end" />
<SelectOption value="right-start" />
<SelectOption value="right-end" />
</Select>
</div>
<div style={{ border: '1px solid' }}>
<Checkbox
label="isVisible (also set trigger to only manual to programmatically control it)"
isChecked={isVisible}
onChange={checked => setIsVisible(checked)}
aria-label="isVisible"
id="is_visible"
/>
</div>
<div style={{ border: '1px solid' }}>
Entry delay (ms){' '}
<TextInput
value={entryDelayInput}
type="number"
onChange={val => setEntryDelayInput(val)}
aria-label="entry delay"
/>
Exit delay (ms) <TextInput
value={exitDelayInput}
type="number"
onChange={val => setExitDelayInput(val)}
aria-label="exit delay"
/>
Animation duration (ms){' '}
<TextInput
value={animationDuration}
type="number"
onChange={val => setAnimationDuration(val)}
aria-label="animation duration"
/>
</div>
<div style={{ border: '1px solid' }}>
flip behavior examples (enableFlip has to be true). "flip" will try to flip the tooltip to the opposite of the
starting position. The second option ensures that there are 3 escape positions for every possible starting
position (default). This setting is ignored if position prop is set to 'auto'.
<Select
onToggle={() => setFlipSelectOpen(!flipSelectOpen)}
onSelect={(event, selection) => {
console.log(selection);
setFlipBehavior(selection);
setFlipSelectOpen(false);
}}
isOpen={flipSelectOpen}
selections={flipBehavior}
menuAppendTo={() => document.body}
>
<SelectOption value="flip" />
<SelectOption value="clockwise">['top', 'right', 'bottom', 'left', 'top', 'right', 'bottom']</SelectOption>
</Select>
</div>
</div>
<div id="tooltip-boundary" className="tooltip-box" ref={tipBoxRef}>
<Tooltip
content={
<div>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam id feugiat augue, nec fringilla turpis.
</div>
}
trigger={trigger.join(' ')}
enableFlip={enableFlip}
flipBehavior={flipBehavior === 'flip' ? 'flip' : ['top', 'right', 'bottom', 'left', 'top', 'right', 'bottom']}
position={position}
isVisible={isVisible}
entryDelay={entryDelayInput}
exitDelay={exitDelayInput}
animationDuration={animationDuration}
isContentLeftAligned={contentLeftAligned}
appendTo={() => document.getElementById('tooltip-boundary')}
>
<Button className="tooltip-button">Tooltip</Button>
</Tooltip>
</div>
</>
);
};
```