Skip to content

Commit

Permalink
[Tooltip] Component and Hook
Browse files Browse the repository at this point in the history
  • Loading branch information
atomiks committed Apr 3, 2024
1 parent b39398a commit bd349cb
Show file tree
Hide file tree
Showing 32 changed files with 996 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import * as React from 'react';
import { Tooltip } from '@mui/base/Tooltip';
import { styled } from '@mui/system';

export default function UnstyledTooltipIntroduction() {
return (
<Tooltip anchorGap={5}>
<Tooltip.AnchorFragment>
<AnchorButton type="button">Anchor</AnchorButton>
</Tooltip.AnchorFragment>
<TooltipContent>Tooltip</TooltipContent>
</Tooltip>
);
}

const blue = {
400: '#3399FF',
600: '#0072E6',
800: '#004C99',
};

export const TooltipContent = styled(Tooltip.Content)`
${({ theme }) => `
background: ${theme.palette.mode === 'dark' ? 'white' : '#333'};
color: ${theme.palette.mode === 'dark' ? 'black' : 'white'};
padding: 4px 6px;
border-radius: 4px;
font-size: 95%;
`}
`;

export const AnchorButton = styled('button')`
border: none;
background: ${blue[600]};
color: white;
padding: 8px 16px;
border-radius: 4px;
font-size: 16px;
&:focus-visible {
outline: 2px solid ${blue[400]};
outline-offset: 2px;
}
&:hover,
&[data-state='open'] {
background: ${blue[800]};
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import * as React from 'react';
import { Tooltip } from '@mui/base/Tooltip';
import { styled } from '@mui/system';

export default function UnstyledTooltipIntroduction() {
return (
<Tooltip anchorGap={5}>
<Tooltip.AnchorFragment>
<AnchorButton type="button">Anchor</AnchorButton>
</Tooltip.AnchorFragment>
<TooltipContent>Tooltip</TooltipContent>
</Tooltip>
);
}

const blue = {
400: '#3399FF',
600: '#0072E6',
800: '#004C99',
};

export const TooltipContent = styled(Tooltip.Content)`
${({ theme }) => `
background: ${theme.palette.mode === 'dark' ? 'white' : '#333'};
color: ${theme.palette.mode === 'dark' ? 'black' : 'white'};
padding: 4px 6px;
border-radius: 4px;
font-size: 95%;
`}
`;

export const AnchorButton = styled('button')`
border: none;
background: ${blue[600]};
color: white;
padding: 8px 16px;
border-radius: 4px;
font-size: 16px;
&:focus-visible {
outline: 2px solid ${blue[400]};
outline-offset: 2px;
}
&:hover,
&[data-state='open'] {
background: ${blue[800]};
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<Tooltip anchorGap={5}>
<Tooltip.AnchorFragment>
<AnchorButton type="button">Anchor</AnchorButton>
</Tooltip.AnchorFragment>
<TooltipContent>Tooltip</TooltipContent>
</Tooltip>
128 changes: 125 additions & 3 deletions docs/data/base/components/tooltip/tooltip.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,136 @@
---
productId: base-ui
title: React Tooltip component
components: Tooltip, TooltipContent, TooltipAnchorFragment, TooltipDelayGroup
githubLabel: 'component: tooltip'
waiAria: https://www.w3.org/WAI/ARIA/apg/patterns/tooltip/
---

# Tooltip 🚧
# Tooltip

<p class="description">Tooltips display informative text when users hover over, focus on, or tap an element.</p>

:::warning
The Base UI Tooltip component isn't available yet, but you can upvote [this GitHub issue](https://github.com/mui/base-ui/issues/32) to see it arrive sooner.
{{"component": "modules/components/ComponentLinkHeader.js", "design": false}}

{{"component": "modules/components/ComponentPageTabs.js"}}

## Introduction

{{"demo": "UnstyledTooltipIntroduction", "defaultCodeOpen": false, "bg": "gradient"}}

## Component

```jsx
import { Tooltip } from '@mui/base/Tooltip';
```

### Anatomy

The `Tooltip` component is composed of a root component that contains two main subcomponents: `AnchorFragment` and `Content`.

```jsx
<Tooltip>
<Tooltip.AnchorFragment />
<Tooltip.Content>
<Tooltip.Arrow />
</Tooltip.Content>
</Tooltip>
```

- `Content` is the tooltip element itself.
- `AnchorFragment` provides props for its child element that lets the `Content` element be anchored to it.
- `Arrow` is an optional element for displaying a caret (or triangle) that points to the center of the anchor.

```jsx
<Tooltip>
<Tooltip.AnchorFragment>
<button type="button">Anchor</button>
</Tooltip.AnchorFragment>
<Tooltip.Content>Tooltip</Tooltip.Content>
</Tooltip>
```

### Placement

By default, the tooltip is placed on the top side of its anchor. To change this, use the `placement` prop:

```jsx
<Tooltip placement="right">
<Tooltip.AnchorFragment>
<button type="button">Anchor</button>
</Tooltip.AnchorFragment>
<Tooltip.Content>Tooltip</Tooltip.Content>
</Tooltip>
```

There are 12 possible placements:

- Centered placements: `top`, `right`, `bottom`, `left`.
- Edge-aligned placements: `top-start`, `top-end`, `right-start`, `right-end`, `bottom-start`, `bottom-end`, `left-start`, `left-end`.

The edge-aligned placements are logical, adapting to the writing direction (LTR or RTL) as expected.

### Anchor gap

To increase the gap between the anchor and its tooltip, use the `anchorGap` prop:

```jsx
<Tooltip anchorGap={10}>
```

### Delay

To delay the tooltip from showing or hiding, use the `delay` prop, which represents how long the tooltip will wait after being triggered to show in milliseconds:

Check warning on line 83 in docs/data/base/components/tooltip/tooltip.md

View workflow job for this annotation

GitHub Actions / runner / vale

[vale] reported by reviewdog 🐶 [Google.Will] Avoid using 'will'. Raw Output: {"message": "[Google.Will] Avoid using 'will'.", "location": {"path": "docs/data/base/components/tooltip/tooltip.md", "range": {"start": {"line": 83, "column": 106}}}, "severity": "WARNING"}

```jsx
<Tooltip delay={200}>
```

The open and close delay can be separately configured:

```jsx
<Tooltip delay={{ open: 500, close: 200 }}>
```

### Open state

To control the tooltip with external state, use the `open` and `onOpenChange` props:

```jsx
function App() {
const [open, setOpen] = React.useState(false);
return (
<Tooltip open={open} onOpenChange={setOpen}>
{/* Subcomponents */}
</Tooltip>
);
}
```

### Default open

To show the tooltip initially while leaving it uncontrolled, use the `defaultOpen` prop:

```jsx
<Tooltip defaultOpen>
```

### Hoverable content

To prevent the content inside from being hoverable, use the `disableHoverableContent` prop:

```jsx
<Tooltip disableHoverableContent>
```

:::info
This should only be disabled when necessary, such as in high-density UIs where tooltips can block other controls.
:::

### Touch input

To prevent the tooltip from showing when using touch input, use the `allowTouch` prop:

```jsx
<Tooltip allowTouch={false}>
```
13 changes: 13 additions & 0 deletions docs/data/base/pagesApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,19 @@ module.exports = [
pathname: '/base-ui/react-textarea-autosize/components-api/#textarea-autosize',
title: 'TextareaAutosize',
},
{ pathname: '/base-ui/react-tooltip/components-api/#tooltip', title: 'Tooltip' },
{
pathname: '/base-ui/react-tooltip/components-api/#tooltip-anchor-fragment',
title: 'TooltipAnchorFragment',
},
{
pathname: '/base-ui/react-tooltip/components-api/#tooltip-content',
title: 'TooltipContent',
},
{
pathname: '/base-ui/react-tooltip/components-api/#tooltip-delay-group',
title: 'TooltipDelayGroup',
},
{
pathname: '/base-ui/react-autocomplete/hooks-api/#use-autocomplete',
title: 'useAutocomplete',
Expand Down
14 changes: 14 additions & 0 deletions docs/pages/base-ui/api/tooltip-anchor-fragment.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"props": {},
"name": "TooltipAnchorFragment",
"imports": [
"import { TooltipAnchorFragment } from '@mui/base/Tooltip';",
"import { TooltipAnchorFragment } from '@mui/base';"
],
"classes": [],
"muiName": "TooltipAnchorFragment",
"filename": "/packages/mui-base/src/Tooltip/TooltipAnchorFragment.tsx",
"inheritance": null,
"demos": "<ul><li><a href=\"/base-ui/react-tooltip/\">Tooltip</a></li></ul>",
"cssComponent": false
}
17 changes: 17 additions & 0 deletions docs/pages/base-ui/api/tooltip-content.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"props": {
"className": { "type": { "name": "union", "description": "func<br>&#124;&nbsp;string" } },
"render": { "type": { "name": "func" } }
},
"name": "TooltipContent",
"imports": [
"import { TooltipContent } from '@mui/base/Tooltip';",
"import { TooltipContent } from '@mui/base';"
],
"classes": [],
"muiName": "TooltipContent",
"filename": "/packages/mui-base/src/Tooltip/TooltipContent.tsx",
"inheritance": null,
"demos": "<ul><li><a href=\"/base-ui/react-tooltip/\">Tooltip</a></li></ul>",
"cssComponent": false
}
14 changes: 14 additions & 0 deletions docs/pages/base-ui/api/tooltip-delay-group.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"props": {},
"name": "TooltipDelayGroup",
"imports": [
"import { TooltipDelayGroup } from '@mui/base/Tooltip';",
"import { TooltipDelayGroup } from '@mui/base';"
],
"classes": [],
"muiName": "TooltipDelayGroup",
"filename": "/packages/mui-base/src/Tooltip/TooltipDelayGroup.tsx",
"inheritance": null,
"demos": "<ul><li><a href=\"/base-ui/react-tooltip/\">Tooltip</a></li></ul>",
"cssComponent": false
}
16 changes: 16 additions & 0 deletions docs/pages/base-ui/api/tooltip.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"props": {},
"name": "Tooltip",
"imports": [
"import { Tooltip } from '@mui/base/Tooltip';",
"import { Tooltip } from '@mui/base';"
],
"classes": [],
"spread": true,
"themeDefaultProps": true,
"muiName": "Tooltip",
"filename": "/packages/mui-base/src/Tooltip/Tooltip.tsx",
"inheritance": null,
"demos": "<ul><li><a href=\"/base-ui/react-tooltip/\">Tooltip</a></li></ul>",
"cssComponent": false
}
60 changes: 60 additions & 0 deletions docs/pages/base-ui/api/use-tooltip.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
{
"parameters": {
"alignmentOffset": { "type": { "name": "number", "description": "number" }, "default": "0" },
"allowTouch": { "type": { "name": "boolean", "description": "boolean" }, "default": "true" },
"anchorGap": { "type": { "name": "number", "description": "number" }, "default": "0" },
"defaultOpen": { "type": { "name": "boolean", "description": "boolean" } },
"delay": {
"type": {
"name": "number | { open?: number; close?: number }",
"description": "number | { open?: number; close?: number }"
},
"default": "0"
},
"disableHoverableContent": {
"type": { "name": "boolean", "description": "boolean" },
"default": "false"
},
"onOpenChange": {
"type": {
"name": "(isOpen: boolean, event: Event) =&gt; void",
"description": "(isOpen: boolean, event: Event) =&gt; void"
}
},
"open": { "type": { "name": "boolean", "description": "boolean" } },
"placement": {
"type": { "name": "Placement", "description": "Placement" },
"default": "'top'"
},
"type": {
"type": {
"name": "&#39;label&#39; | &#39;description&#39; | &#39;visual-only&#39;",
"description": "&#39;label&#39; | &#39;description&#39; | &#39;visual-only&#39;"
},
"default": "'description'"
}
},
"returnValue": {
"getAnchorProps": {
"type": {
"name": "(externalProps?: React.HTMLAttributes&lt;HTMLElement&gt;) =&gt; React.HTMLAttributes&lt;HTMLElement&gt;",
"description": "(externalProps?: React.HTMLAttributes&lt;HTMLElement&gt;) =&gt; React.HTMLAttributes&lt;HTMLElement&gt;"
},
"required": true
},
"getTooltipProps": {
"type": {
"name": "(externalProps?: React.HTMLAttributes&lt;HTMLElement&gt;) =&gt; React.HTMLAttributes&lt;HTMLElement&gt;",
"description": "(externalProps?: React.HTMLAttributes&lt;HTMLElement&gt;) =&gt; React.HTMLAttributes&lt;HTMLElement&gt;"
},
"required": true
}
},
"name": "useTooltip",
"filename": "/packages/mui-base/src/useTooltip/useTooltip.ts",
"imports": [
"import { useTooltip } from '@mui/base/useTooltip';",
"import { useTooltip } from '@mui/base';"
],
"demos": "<ul></ul>"
}
Loading

0 comments on commit bd349cb

Please sign in to comment.