SolutionsCase StudiesAI ToolsResourcesAboutContact
Get Your Free AI Automation Audit Book a Free 30-Minute Strategy Call
Playground~/frontend Open editor

~/css/tooltips

8 CSS Tooltips

8 Pure CSSPublished 2026-10-04Free · no sign-up

Eight tooltip patterns that work with a mouse, a keyboard and a screen reader: a basic tip with an arrow, four placements, a form help icon, a frosted glass tip, toolbar shortcuts, a click-to-open toggletip using the popover attribute, a profile hover card and a quick attr()-based tip.

01. Accessible CSS Tooltip

TooltipAccessible

A tooltip that appears on hover and on keyboard focus, with a small arrow drawn by a rotated square. The tip text is a real element linked with aria-describedby, so screen readers hear it, and it stays visible while the pointer moves onto it.

View code
<span class="tip">
  <button aria-describedby="tip1">Export</button>
  <span role="tooltip" id="tip1">Download this report as a CSV file</span>
</span>
.tip { position: relative; display: inline-block; font-family: Inter, system-ui, sans-serif; }
.tip button { padding: 10px 18px; border: 1px solid #3a4256; border-radius: 10px; background: #1a1f2c; color: #fff; font: 600 14px Inter, sans-serif; cursor: pointer; }
.tip [role=tooltip] { position: absolute; bottom: calc(100% + 10px); left: 50%; width: max-content; max-width: 220px; padding: 8px 10px; border-radius: 8px; background: #fff; color: #101828; font-size: 13px; line-height: 1.4; text-align: center; opacity: 0; visibility: hidden; transform: translate(-50%, 4px); transition: opacity .15s, transform .15s, visibility .15s; }
.tip [role=tooltip]::after { content: ""; position: absolute; top: 100%; left: 50%; width: 10px; height: 10px; background: #fff; transform: translate(-50%, -5px) rotate(45deg); }
.tip:hover [role=tooltip], .tip:focus-within [role=tooltip] { opacity: 1; visibility: visible; transform: translate(-50%, 0); }
.tip button:focus-visible { outline: 2px solid #9db8ff; outline-offset: 2px; }

02. Tooltips on Four Sides

TooltipPlacement

One tooltip component placed on the top, right, bottom and left of its trigger with a data attribute. Each side has its own arrow direction, and the shared rules live on the base class so adding a placement only takes two short declarations.

View code
<div class="sides">
  <button class="t4" data-side="right" aria-describedby="p2">Right<span role="tooltip" id="p2">To the right</span></button>
  <button class="t4" data-side="left" aria-describedby="p4">Left<span role="tooltip" id="p4">To the left</span></button>
  <button class="t4" data-side="top" aria-describedby="p1">Top<span role="tooltip" id="p1">Above the button</span></button>
  <button class="t4" data-side="bottom" aria-describedby="p3">Bottom<span role="tooltip" id="p3">Below the button</span></button>
</div>
.sides { box-sizing: border-box; max-width: 100%; display: grid; grid-template-columns: repeat(2, auto); gap: 70px 110px; font-family: Inter, system-ui, sans-serif; }
.t4 { position: relative; padding: 10px 16px; border: 1.5px solid #d0d5dd; border-radius: 10px; background: #fff; color: #101828; font: 600 14px Inter, sans-serif; cursor: pointer; }
.t4 [role=tooltip] { position: absolute; z-index: 2; width: max-content; padding: 6px 10px; border-radius: 6px; background: #101828; color: #fff; font-size: 12.5px; font-weight: 500; opacity: 0; pointer-events: none; transition: opacity .15s; }
.t4:hover [role=tooltip], .t4:focus-visible [role=tooltip] { opacity: 1; }
.t4[data-side=top] [role=tooltip] { bottom: calc(100% + 8px); left: 50%; transform: translateX(-50%); }
.t4[data-side=bottom] [role=tooltip] { top: calc(100% + 8px); left: 50%; transform: translateX(-50%); }
.t4[data-side=right] [role=tooltip] { left: calc(100% + 8px); top: 50%; transform: translateY(-50%); }
.t4[data-side=left] [role=tooltip] { right: calc(100% + 8px); top: 50%; transform: translateY(-50%); }
.t4:focus-visible { outline: 2px solid #2563eb; outline-offset: 2px; }

03. Info Icon Tooltip

HelpForm

The small i icon next to a form label that explains a field. The icon is a real button with an accessible name, so it can be reached with Tab, and the explanation shows on focus as well as hover, which matters on touch screens and for keyboard users.

View code
<div class="fld">
  <label for="tax">VAT number</label>
  <span class="info">
    <button type="button" aria-label="What is a VAT number?" aria-describedby="vat-tip">i</button>
    <span role="tooltip" id="vat-tip">Only needed for business orders inside the EU. You can add it later.</span>
  </span>
  <input id="tax" placeholder="GB123456789">
</div>
.fld { display: grid; grid-template-columns: auto 1fr; align-items: center; gap: 8px; width: min(320px, 88vw); color: #344054; font: 600 14px Inter, system-ui, sans-serif; }
.fld input { grid-column: 1 / -1; padding: 10px 12px; border: 1.5px solid #d0d5dd; border-radius: 10px; font: 15px Inter, sans-serif; }
.info { position: relative; justify-self: start; }
.info button { width: 20px; height: 20px; border: 0; border-radius: 50%; background: #e4e7ec; color: #344054; font: 700 12px Georgia, serif; cursor: help; }
.info button:focus-visible { outline: 2px solid #2563eb; outline-offset: 2px; }
.info [role=tooltip] { position: absolute; left: 30px; top: 50%; z-index: 2; width: 220px; padding: 9px 11px; border-radius: 8px; background: #101828; color: #fff; font-size: 12.5px; font-weight: 500; line-height: 1.45; transform: translateY(-50%); display: none; }
.info:hover [role=tooltip], .info:focus-within [role=tooltip] { display: block; }

04. Glass Tooltip

GlassTooltip

A frosted tooltip for colourful or photographic backgrounds. backdrop-filter blurs whatever sits behind it, a hairline white border separates it from the background, and the text stays white on a dark tint so it remains readable.

View code
<div class="gbg">
  <span class="gtip">
    <button aria-describedby="g1">Hover me</button>
    <span role="tooltip" id="g1">Frosted with backdrop-filter</span>
  </span>
</div>
.gbg { display: grid; place-items: center; width: min(380px, 90vw); height: 200px; border-radius: 18px; background: radial-gradient(circle at 25% 30%, #f472b6, transparent 50%), radial-gradient(circle at 75% 70%, #22d3ee, transparent 50%), #1e1b4b; }
.gtip { position: relative; }
.gtip button { padding: 10px 18px; border: 1px solid rgba(255,255,255,.4); border-radius: 999px; background: rgba(255,255,255,.12); color: #fff; font: 600 14px Inter, system-ui, sans-serif; cursor: pointer; }
.gtip [role=tooltip] { position: absolute; bottom: calc(100% + 12px); left: 50%; width: max-content; padding: 8px 12px; border: 1px solid rgba(255,255,255,.3); border-radius: 10px; background: rgba(15,18,34,.55); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); color: #fff; font: 500 13px Inter, sans-serif; transform: translateX(-50%) scale(.95); opacity: 0; transition: opacity .15s, transform .15s; pointer-events: none; }
.gtip:hover [role=tooltip], .gtip:focus-within [role=tooltip] { opacity: 1; transform: translateX(-50%) scale(1); }
.gtip button:focus-visible { outline: 2px solid #fff; outline-offset: 3px; }

05. Tooltip with Keyboard Shortcut

ToolbarKbd

Icon toolbar buttons with tooltips that show the action name and its keyboard shortcut in kbd elements, like desktop apps. Each icon button has an aria-label, and the tooltip repeats it visually, so sighted mouse users learn the shortcut too.

View code
<div class="bar" role="toolbar" aria-label="Text formatting">
  <button aria-label="Bold" class="tb"><b>B</b><span class="tp" aria-hidden="true">Bold <kbd>Ctrl</kbd><kbd>B</kbd></span></button>
  <button aria-label="Italic" class="tb"><i>I</i><span class="tp" aria-hidden="true">Italic <kbd>Ctrl</kbd><kbd>I</kbd></span></button>
  <button aria-label="Link" class="tb">&#128279;<span class="tp" aria-hidden="true">Link <kbd>Ctrl</kbd><kbd>K</kbd></span></button>
</div>
.bar { display: flex; gap: 4px; padding: 6px; border: 1px solid #2c3346; border-radius: 12px; background: #151a26; }
.tb { position: relative; width: 38px; height: 38px; border: 0; border-radius: 8px; background: none; color: #e7ebf5; font: 16px Georgia, serif; cursor: pointer; }
.tb:hover, .tb:focus-visible { background: #262d3e; outline: none; }
.tp { position: absolute; top: calc(100% + 10px); left: 50%; display: flex; align-items: center; gap: 4px; width: max-content; padding: 6px 8px; border-radius: 8px; background: #fff; color: #101828; font: 600 12px Inter, system-ui, sans-serif; transform: translateX(-50%); opacity: 0; pointer-events: none; transition: opacity .12s; }
.tp kbd { padding: 1px 5px; border: 1px solid #d0d5dd; border-bottom-width: 2px; border-radius: 4px; background: #f9fafb; font: 600 11px "JetBrains Mono", monospace; }
.tb:hover .tp, .tb:focus-visible .tp { opacity: 1; }

06. Toggletip with the Popover API

PopoverModern

A click-to-open toggletip built with the HTML popover attribute: no JavaScript, light dismiss when you click elsewhere, and Escape closes it. The button points at the popover with popovertarget, and the browser handles the open state for assistive technology.

View code
<div class="pop-wrap">
  <p>Shipping is free over $60 <button class="q" popovertarget="ship-pop" aria-label="About free shipping">?</button></p>
  <div id="ship-pop" popover class="pop">Free shipping applies to standard delivery within the country. Express is always charged.</div>
</div>
.pop-wrap { font: 500 15px Inter, system-ui, sans-serif; color: #101828; }
.pop-wrap p { display: flex; align-items: center; gap: 8px; margin: 0; }
.q { width: 22px; height: 22px; border: 0; border-radius: 50%; background: #101828; color: #fff; font: 700 12px Inter, sans-serif; cursor: pointer; anchor-name: --q; }
.q:focus-visible { outline: 2px solid #2563eb; outline-offset: 2px; }
.pop { position-anchor: --q; top: anchor(bottom); left: anchor(center); translate: -50% 10px; width: 240px; margin: 0; padding: 12px 14px; border: 0; border-radius: 10px; background: #101828; color: #fff; font: 500 13px/1.5 Inter, sans-serif; box-shadow: 0 12px 30px -10px rgba(16,24,40,.5); }

07. Rich Profile Hover Card

CardHover

A larger hover card for usernames that previews the profile with an avatar, a short bio and follower count. It opens after a short delay so it does not flash while the pointer passes over, and it can also be reached with Tab on the link.

View code
<p class="mention">Design by <span class="hc"><a href="#" aria-describedby="hc1">@mira.studio</a>
  <span class="card" id="hc1" role="tooltip"><span class="av" aria-hidden="true">M</span><b>Mira Okafor</b><em>Ceramicist and illustrator in Lisbon. 4,200 followers.</em></span></span></p>
.mention { box-sizing: border-box; max-width: 100%; margin: 0; color: #c9d1e2; font: 500 16px Inter, system-ui, sans-serif; }
.mention { position: relative; }
.hc { position: static; }
.hc a { color: #93c5fd; font-weight: 700; text-decoration: none; }
.hc a:focus-visible { outline: 2px solid #93c5fd; outline-offset: 2px; border-radius: 3px; }
.card { position: absolute; top: calc(100% + 10px); left: 0; display: grid; grid-template-columns: 44px 1fr; gap: 2px 12px; box-sizing: border-box; width: min(260px, 100%); padding: 14px; border: 1px solid #2c3346; border-radius: 14px; background: #151a26; box-shadow: 0 18px 40px -16px #000; opacity: 0; visibility: hidden; transition: opacity .15s, visibility .15s; transition-delay: 0s; }
.hc:hover .card, .hc:focus-within .card { opacity: 1; visibility: visible; transition-delay: .3s; }
.av { grid-row: span 2; display: grid; place-items: center; width: 44px; height: 44px; border-radius: 50%; background: linear-gradient(135deg, #f59e0b, #ec4899); color: #fff; font-weight: 800; }
.card b { color: #fff; font-size: 15px; }
.card em { color: #9aa4b8; font-style: normal; font-size: 13px; line-height: 1.45; }

08. Data Attribute Tooltip

Pure CSSQuick

The quickest tooltip: the text lives in a data-tip attribute and is shown by ::after with content: attr(data-tip). It is handy for decorative hints in prototypes, but pseudo-element text is not reliably read aloud, so the same text is repeated in aria-label.

View code
<div class="attr">
  <a href="#" class="dt" data-tip="Opens in the same tab" aria-label="Pricing, opens in the same tab">Pricing</a>
  <a href="#" class="dt" data-tip="Updated weekly" aria-label="Changelog, updated weekly">Changelog</a>
</div>
.attr { display: flex; gap: 32px; font: 600 15px Inter, system-ui, sans-serif; }
.dt { position: relative; color: #1d4ed8; text-decoration: none; border-bottom: 1px dashed #93c5fd; }
.dt::after { content: attr(data-tip); position: absolute; bottom: calc(100% + 8px); left: 50%; width: max-content; padding: 6px 9px; border-radius: 6px; background: #1d4ed8; color: #fff; font-size: 12px; font-weight: 500; transform: translateX(-50%); opacity: 0; transition: opacity .15s; pointer-events: none; }
.dt:hover::after, .dt:focus-visible::after { opacity: 1; }
.dt:focus-visible { outline: 2px solid #1d4ed8; outline-offset: 3px; }

About these CSS Tooltips

Hover is not enough

A tooltip that only appears on hover is invisible to keyboard and touch users. Show it on :focus-visible or :focus-within as well as :hover, and make sure the trigger can receive focus, which means using a button or link rather than a plain span.

Connect the text

Link the tooltip to its trigger with aria-describedby and give it role="tooltip". Screen readers then read the tip after the button's name. Keep tooltips short and never put essential information or links only inside them.

Toggletips for touch

On phones there is no hover, so an information bubble should open on tap. The HTML popover attribute with popovertarget does this without JavaScript and closes on Escape or a click elsewhere.

Avoid flicker

Add a short delay before a large hover card appears, as the profile card does with transition-delay, so it does not flash when the pointer only passes over the link.

Frequently asked questions

Is the title attribute a good tooltip?

Not on its own. It does not appear on focus or touch and has unpredictable timing. Use a real element with aria-describedby.

Can tooltips contain links?

No. If it needs links or buttons, use a popover or a dialog instead.

Do these need JavaScript?

No. All eight are CSS and HTML; the popover demo uses a built-in browser feature.