Tooltip
A short hint on hover or focus.
<tooltip.Tooltip content="Add to library"><button type="button">Hover me</button></tooltip.Tooltip>Installation
Run the command in the app module.
gx add tooltipThe command writes these files.
| File | Path in the app |
|---|---|
Tooltip.gx |
ui/tooltip/Tooltip.gx |
Tooltip.fixtures.go |
ui/tooltip/Tooltip.fixtures.go |
styles.go |
ui/tooltip/styles.go |
Copy each file to its path in the app. Change each import of a registry package to the path of that package in the app.
package tooltip
props {
// Content is the text of the tooltip. An empty value renders no tooltip.
Content string = ""
// Side sets the edge of the trigger that the tooltip appears on: Top, Bottom, Left or Right.
Side Side = Top
// Class adds classes to the root element.
Class string = ""
// Children is the element that shows the tooltip on hover or on keyboard focus.
Children gx.Node
// Attrs adds HTML attributes to the root element.
Attrs gx.Attrs = nil
}
<span class={gx.Cx("group/tooltip relative inline-flex", p.Class)} {...p.Attrs}>
{p.Children}
if p.Content != "" {
<span role="tooltip" class={gx.Cx("pointer-events-none invisible absolute z-50 w-max max-w-64 rounded-md bg-foreground px-3 py-1.5 text-xs text-balance text-background opacity-0 scale-95 transition-[opacity,scale,translate,visibility] duration-150 motion-reduce:transition-none group-hover/tooltip:visible group-hover/tooltip:opacity-100 group-hover/tooltip:scale-100 group-has-[:focus-visible]/tooltip:visible group-has-[:focus-visible]/tooltip:opacity-100 group-has-[:focus-visible]/tooltip:scale-100", sideClass[p.side()])}>
{p.Content}
<span aria-hidden="true" class={gx.Cx("absolute size-2.5 rotate-45 rounded-[2px] bg-foreground", arrowClass[p.side()])}></span>
</span>
}
</span>package tooltip
import "github.com/alternayte/gx"
var TooltipFixtures = gx.Fixtures[TooltipProps]{
"Top": {Content: "Add to library", Children: gx.El("button", gx.Attrs{{Key: "type", Value: "button"}}, gx.Text("Hover me"))},
"Right": {Content: "Add to library", Side: Right, Children: gx.El("button", gx.Attrs{{Key: "type", Value: "button"}}, gx.Text("Hover me"))},
"Bottom": {Content: "Add to library", Side: Bottom, Children: gx.El("button", gx.Attrs{{Key: "type", Value: "button"}}, gx.Text("Hover me"))},
"Left": {Content: "Add to library", Side: Left, Children: gx.El("button", gx.Attrs{{Key: "type", Value: "button"}}, gx.Text("Hover me"))},
}package tooltip
import "github.com/alternayte/gx"
// Side is the edge a tooltip appears on.
type Side string
// The sides of tooltip.Tooltip.
const (
Top Side = "top"
Bottom Side = "bottom"
Left Side = "left"
Right Side = "right"
)
// The content sits 5px off the trigger, the height of the arrow. It zooms
// from the arrow and slides 2 units from the trigger side. round() keeps the
// centred content on whole pixels, so its text stays sharp.
var sideClass = gx.Enum[Side]{
Top: "bottom-full left-[round(50%,1px)] mb-[5px] origin-bottom -translate-x-[round(50%,1px)] translate-y-2 group-hover/tooltip:translate-y-0 group-has-[:focus-visible]/tooltip:translate-y-0",
Bottom: "top-full left-[round(50%,1px)] mt-[5px] origin-top -translate-x-[round(50%,1px)] -translate-y-2 group-hover/tooltip:translate-y-0 group-has-[:focus-visible]/tooltip:translate-y-0",
Left: "right-full top-[round(50%,1px)] mr-[5px] origin-right -translate-y-[round(50%,1px)] translate-x-2 group-hover/tooltip:translate-x-0 group-has-[:focus-visible]/tooltip:translate-x-0",
Right: "left-full top-[round(50%,1px)] ml-[5px] origin-left -translate-y-[round(50%,1px)] -translate-x-2 group-hover/tooltip:translate-x-0 group-has-[:focus-visible]/tooltip:translate-x-0",
}
// The arrow is a rotated square whose centre lies 2px inside the edge of
// the content, as the reference draws it.
var arrowClass = gx.Enum[Side]{
Top: "top-full left-[round(50%,1px)] -translate-x-1/2 -translate-y-[calc(50%+2px)]",
Bottom: "bottom-full left-[round(50%,1px)] -translate-x-1/2 translate-y-[calc(50%+2px)]",
Left: "left-full top-[round(50%,1px)] -translate-x-[calc(50%+2px)] -translate-y-1/2",
Right: "right-full top-[round(50%,1px)] translate-x-[calc(50%+2px)] -translate-y-1/2",
}
// side returns the side of one tooltip; a zero value is Top.
func (p TooltipProps) side() Side {
if p.Side == "" {
return Top
}
return p.Side
}The theme must define these tokens: --foreground, --background.
Usage
<tooltip.Tooltip content="Add to library">
<button.Button variant={button.Outline}>Add</button.Button>
</tooltip.Tooltip>The tooltip is CSS only. It shows on hover and on keyboard focus, with an arrow that points at the control. Side selects the edge: tooltip.Top (default), tooltip.Bottom, tooltip.Left or tooltip.Right.
The tooltip fades, zooms and slides in from the control. A user who asks for reduced motion gets no transition.
Examples
Top
<tooltip.Tooltip content="Add to library"><button type="button">Hover me</button></tooltip.Tooltip>Right
<tooltip.Tooltip content="Add to library" side={tooltip.Right}><button type="button">Hover me</button></tooltip.Tooltip>Bottom
<tooltip.Tooltip content="Add to library" side={tooltip.Bottom}>
<button type="button">Hover me</button>
</tooltip.Tooltip>Left
<tooltip.Tooltip content="Add to library" side={tooltip.Left}><button type="button">Hover me</button></tooltip.Tooltip>API reference
A tag sets a prop by its name with a lower-case first letter: Class is class.
tooltip.Tooltip
| Prop | Type | Default | Description |
|---|---|---|---|
Content |
string |
"" |
Content is the text of the tooltip. An empty value renders no tooltip. |
Side |
Side |
Top |
Side sets the edge of the trigger that the tooltip appears on: Top, Bottom, Left or Right. |
Class |
string |
"" |
Class adds classes to the root element. |
Children |
gx.Node |
Required | Children is the element that shows the tooltip on hover or on keyboard focus. |
Attrs |
gx.Attrs |
nil |
Attrs adds HTML attributes to the root element. |
Do and do not
Do
- Keep the text to a few words.
- Wrap a control that needs a name.
Don't
- Do not put essential information only in a tooltip.
- Do not put a link inside a tooltip.
Keyboard
| Key | Action |
|---|---|
| Tab | The tooltip appears when the control takes keyboard focus. |