Skip to content

Commit

Permalink
Write documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
connor-baer committed Mar 25, 2024
1 parent 2c3d96b commit 97dcd2b
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 19 deletions.
62 changes: 60 additions & 2 deletions packages/circuit-ui/components/Tooltip/Tooltip.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,66 @@ import * as Stories from './Tooltip.stories';

<Status variant="experimental" />

A floating bubble of information that clarifies the purpose of otherwise ambiguous controls/tools.
Tooltips display additional information upon hover or focus that is contextual, helpful, and nonessential to clarify the purpose of otherwise ambiguous interactive elements.

<Story of={Stories.Base} />

<Props />

## Usage

Tooltips hide information by default and require user interaction to be shown. They should be used as a last resort when space truly is limited and the information cannot be shown inline.

A Tooltip must be used with an interactive, focusable element such as a button, link or input. When wrapping a custom component or an inline function, ensure that the [`ref` is forwarded](https://react.dev/reference/react/forwardRef).

The label must be a single unformatted string. Use a [Toggletip](Components/Toggletip/Docs) instead if the content should be structured or interactive.

The Tooltip works without JavaScript as long as the parent element is [positioned](https://developer.mozilla.org/en-US/docs/Web/CSS/position#types_of_positioning). When JavaScript is available, the Tooltip is progressively enhanced to place itself within the viewport.

## Variations

### Types

<Story of={Stories.Types} />

#### Label

Use the `label` type when the tooltip acts as the wrapped component's label (aka [accessible name](https://w3c.github.io/accname/#dfn-accessible-name)). The label text should state the element's function or action in one or two words maximum.

#### Description

Use the `description` type when the tooltip provides supplemental information about the wrapped component ([accessible description](https://w3c.github.io/accname/#dfn-accessible-description)). The label text should not contain information that is critical for a user to understand the wrapped element. Use sentence-case for the label text and write complete sentences with punctuation unless space is limited. Avoid exceeding 160 characters.

### Placement

By default, the tooltip is positioned above the wrapped component and center-aligned. Use the `placement` prop to specify a different initial position and alignment.

The tooltip automatically flips to the opposite side to stay within the viewport when there isn't enough space available.

<Story of={Stories.Placements} />

---

## Accessibility

### Best practices


- Only interactive elements should trigger tooltips
- Tooltips should directly describe the UI control that triggers them (i.e. do not create a control purely to trigger a tooltip)
- Use `aria-describedby` or `aria-labelledby` to associate the UI control with the tooltip. Avoid `aria-haspopup` and `aria-live`
- Do not use the `title` attribute to create a tooltip
- Do not put essential information in tooltips
- Provide a means to dismiss the tooltip with both keyboard and pointer
- Allow the mouse to easily move over the tooltip without dismissing it
- Do not use a timeout to hide the tooltip


### Resources

- [Tooltips in the time of WCAG 2.1](https://sarahmhigley.com/writing/tooltips-in-wcag-21/) by Sarah Highley
- [Inclusive Components: Tooltip & Toggletips](https://inclusive-components.design/tooltips-toggletips/) by Heydon Pickering

#### Related WCAG success criteria

- 1.4.13: [Content on Hover or Focus](https://www.w3.org/WAI/WCAG21/Understanding/content-on-hover-or-focus.html)

58 changes: 41 additions & 17 deletions packages/circuit-ui/components/Tooltip/Tooltip.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@
*/

import { forwardRef } from 'react';
import { within, userEvent } from '@storybook/testing-library';
import { userEvent } from '@storybook/test';
import { TransferOut, UploadCloud } from '@sumup/icons';

import Button from '../Button/index.js';
import { Stack } from '../../../../.storybook/components/index.js';
import Button, { IconButton } from '../Button/index.js';

import { Tooltip, TooltipProps, TooltipReferenceProps } from './Tooltip.js';

Expand All @@ -29,25 +31,47 @@ export default {
},
};

const Reference = forwardRef<HTMLButtonElement, TooltipReferenceProps>(
(props, ref) => (
<Button {...props} ref={ref} size="s" disabled>
Submit
</Button>
const descriptionProps = {
label: 'This may take a few minutes',
type: 'description',
component: forwardRef<HTMLButtonElement, TooltipReferenceProps>(
(props, ref) => (
<Button {...props} icon={UploadCloud} ref={ref}>
Upload
</Button>
),
),
);
} as const;

const showTooltip = async () => {
await userEvent.tab();
};

export const Base = (args: TooltipProps) => (
<Tooltip {...args} component={Reference} />
<Stack>
<Tooltip {...args} />
</Stack>
);

Base.args = {
label: 'Please fill out all fields',
};
Base.args = descriptionProps;
Base.play = showTooltip;

Base.play = async ({ canvasElement }: { canvasElement: HTMLCanvasElement }) => {
const canvas = within(canvasElement);
const reference = canvas.getByRole('button');
export const Types = (args: TooltipProps) => (
<Stack>
{/* The IconButton uses the Tooltip component under the hood */}
<IconButton icon={TransferOut}>Transfer out</IconButton>
<Tooltip {...args} {...descriptionProps} />
</Stack>
);

await userEvent.hover(reference);
};
Types.play = showTooltip;

export const Placements = (args: TooltipProps) => (
<Stack>
<Tooltip {...args} {...descriptionProps} placement="left" />
<Tooltip {...args} {...descriptionProps} placement="bottom-start" />
<Tooltip {...args} {...descriptionProps} placement="right-end" />
</Stack>
);

Placements.play = showTooltip;

0 comments on commit 97dcd2b

Please sign in to comment.