Skip to content

[css-ui] Standardize tooltip styling and expose as ::tooltip #8930

Open
@LeaVerou

Description

@LeaVerou

Now that popover and anchor positioning are moving forwards, I wonder if it’s time to re-examine standardizing tooltip styling and adding a ::tooltip pseudo-element so that authors can customize it.

History

Since 6 years have passed since then, it seems like a good time to discuss it again. Maybe this time it will bear fruit. 😁

ETA: Apparently there was also a recent Open UI discussion on this with some good discussion.

Problem statement

Default UA tooltips are generally seen as inflexible, slow, and not aesthetically pleasing. Their styling is entirely disconnected from the element they describe (e.g. observe that the font size of the span does not affect the font size of the tooltip at all), and their color scheme is set by the OS, not the page (observe how in dark mode, the tooltip is dark, even when the page is actually not).

MacOS Windows MacOS dark mode
image image image

For these reasons, nearly all popular websites employ some kind of scripting for custom tooltips. NPM packages for tooltips are in the millions of downloads per week. However, the styling employed by the vast majority of cases is actually pretty simple.

A few examples:

Google Facebook Twitter GitHub Google Docs Reddit
image image image image image image

Literally all component libraries include a component for tooltips (OpenUI research), however due to the limitations of components, they have to create an element for something that is conceptually not an element, but a behavior of another element. This results in unpredictable markup and complex selectors (e.g. consider <sl-tooltip>; selectors now need to account for sl-tooltip possibly being anywhere in the tree, consider how a selector like ul > li > ul > li would need to be rewritten).

Older scripts depend on processing all [title] elements on the page, renaming the attribute to data-title or something, and adding event listeners (usually through event delegation). The downside of these scripts is that they don't work in shadow trees, and are often inaccessible.

And of course, there are always the authors that will roll their own, usually also resulting in poor accessibility.

Goals

  • Custom tooltip styling (fonts, backgrounds, colors, shadows etc), including pointers
  • Customization of show/hide animations (one of the major issues with the UA tooltips is how long they take to appear)

Non-goals

  • Tooltips with arbitrary HTML content (these can be done with the popover API)

Proposal

We define a ::tooltip pseudo-element and standardize the default styling through a UA rule, which could look like this:

::tooltip {
	content: attr(title);
	color: InfoText;
	background: InfoBackground;
	font-size: .8rem;
	box-shadow: .1rem .1rem .2rem rgb(0 0 0 / .2);
	transition: 0s 3s visibility;	

	@starting-style {
		visibility: hidden;
	}
}

Notes:

  • To allow for pointers, this needs to allow sub-pseudo-elements.
  • Do we need to restrict the properties that apply to this pseudo-element?
  • Right now tooltip contents are set via the content property, which can be overridden to something else. Is this useful? I can see it being set to totally unrelated attributes, harming accessibility.

Issues

Positioning

As it currently stands, how the tooltip is positioned is still magic. This does make it easier to implement, but makes certain common styles very difficult: how to add a pointer when you don't know how the tooltip and originating element positions relate? We definitely don't want authors to have to deal with positioning tooltips manually, as that is insanely complicated. Perhaps we should expose some info to them about the relative positions of the tooltip and element that they can use in their styling? Maybe via env()? Or, even better, it could be defined in terms of anchor positioning.

I think it's ok if we ship an MVP where pointers are not yet possible (which still covers a large number of use cases), but the design does need to allow for this to become possible in the future. Perhaps by restricting the properties allowed in ::tooltip

Customizing display triggers

As it currently stands, what makes the tooltip to be displayed is still magic. While this is fine, especially for an MVP, it would open up a ton of really nice use cases if this was grounded in specific user action pseudo-classes that generate the tooltip or not. Authors could then generate tooltips on :focus, :focus-within, via interactions on other elements (e.g. :focus + .foo::tooltip), or even through entirely custom interactions (by toggling classes via JS).

Perhaps, if we agree that setting the content property is what generates the box (like ::before and ::after), the default UA styles could look like this:

::tooltip {
	color: TooltipText;
	background: TooltipBackground;
	font-size: .8rem;
	box-shadow: .1rem .1rem .2rem rgb(0 0 0 / .2);
	transition: 0s 3s visibility;	

	@starting-style {
		visibility: hidden;
	}
}

[title]:hover::tooltip {
	content: attr(title);
}

The downside is that this couples the display trigger with the content. If someone wants to override the content, they also need to be up to date with the display triggers used and vice versa.

We could do something like this:

::tooltip {
	content: attr(title);
	color: TooltipText;
	background: TooltipBackground;
	font-size: .8rem;
	box-shadow: .1rem .1rem .2rem rgb(0 0 0 / .2);
	transition: 0s 3s visibility;	
	visibility: hidden;
}

[title]:hover::tooltip {
	visibility: visible;
}

But this implies the box is pre-generated and simply shown, which I don't imagine is desirable for implementations.

::tooltip in SVG

Instead of using a title attribute, SVG supports a <title> element, so when used in SVG, ::tooltip should cover these tooltips as well. However, there is no way to specify something analogous to content: attr(title) that works with that markup pattern, which may be another reason to axe that and have the content be magic (prefixes and suffixes can always be added via ::before and ::after). Or alternatively, we can define a new keyword or function for content that returns the tooltip content, regardless of where it comes from.

Not exactly within the purview of the CSS WG, but it would be nice if in the future we could backport this element into HTML, to cater to the use cases that require more rich tooltip content without having to deal with all the plumbing and positioning manually. I do wonder what web compat would be like — I suspect there must be some clumsy author code out there that assumes there is only a single <title> element on the page, and it contains the document title. Though inline SVG would break those already.

Metadata

Metadata

Assignees

No one assigned

    Labels

    css-ui-4Current Workcss-ui-5open-uiIssues that desire to have Open UI input

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions