A small info icon beside a form label that opens a wrapping help text to its right. Only the icon triggers it: the label ignores the pointer, the icon opts back in.
Also known as: info icon hover text css, help icon tooltip, question mark tooltip css.
<span class="tip-info-icon"> Monthly budget <button type="button" aria-label="About monthly budget" aria-describedby="tip-info-icon-tip"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M12 11v5.5M12 7.6v.1"/></svg></button> <span class="tip-info-icon-tip" id="tip-info-icon-tip" role="tooltip">Spending pauses when you reach this limit. You can raise it at any time.</span> </span>
.tip-info-icon {
--c: var(--tip-color, #3b82f6);
font-size: var(--tip-size, 16px);
position: relative;
display: inline-flex;
align-items: center;
gap: 0.3em;
margin-right: 8em; /* room for the tooltip in this preview */
font-family: system-ui, sans-serif;
font-weight: 600;
pointer-events: none; /* only the icon opens the tooltip */
}
.tip-info-icon button {
display: grid;
place-items: center;
width: 1.6em;
height: 1.6em;
padding: 0;
border: 0;
border-radius: 50%;
background: none;
color: color-mix(in srgb, currentColor 50%, transparent);
cursor: help;
pointer-events: auto;
transition: color 0.2s ease;
}
.tip-info-icon svg {
width: 1.2em;
height: 1.2em;
}
.tip-info-icon:hover button { color: var(--c); }
.tip-info-icon button:focus-visible {
outline: 2px solid var(--c);
outline-offset: 2px;
}
.tip-info-icon-tip {
position: absolute;
top: 50%;
left: calc(100% + 0.7em);
z-index: 10;
width: max-content;
max-width: 13em;
padding: 0.6em 0.8em;
border: 1px solid rgb(15 23 42 / 0.12);
border-radius: 0.55em;
background: #fff;
box-shadow: 0 0.6em 1.2em -0.5em rgb(15 23 42 / 0.35);
color: #334155;
font: 400 0.8em/1.45 system-ui, sans-serif;
text-wrap: balance;
opacity: 0;
visibility: hidden;
pointer-events: none;
transform: translate(-0.5em, -50%);
transition: opacity 0.18s ease, transform 0.25s cubic-bezier(0.2, 0.8, 0.2, 1), visibility 0.25s;
}
.tip-info-icon-tip::before {
content: "";
position: absolute;
top: 50%;
right: 100%;
box-sizing: border-box;
width: 0.75em;
height: 0.75em;
border: inherit;
border-top: 0;
border-right: 0;
border-radius: 0 0 0 0.12em;
background: inherit;
transform: translate(55%, -50%) rotate(45deg);
}
.tip-info-icon:hover .tip-info-icon-tip,
.tip-info-icon:focus-within .tip-info-icon-tip {
opacity: 1;
visibility: visible;
transform: translate(0, -50%);
}
@media (prefers-reduced-motion: reduce) {
.tip-info-icon, .tip-info-icon *, .tip-info-icon::before, .tip-info-icon::after, .tip-info-icon *::before, .tip-info-icon *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}The same effect using Tailwind utility classes. No custom CSS or config needed.
<span class="group pointer-events-none relative mr-36 inline-flex items-center gap-1 font-semibold">
Monthly budget
<button type="button" aria-label="About monthly budget" aria-describedby="tooltip-budget" class="pointer-events-auto grid h-6 w-6 cursor-help place-items-center rounded-full text-slate-400 transition-colors group-hover:text-blue-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" class="h-5 w-5" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M12 11v5.5M12 7.6v.1"/></svg>
</button>
<span id="tooltip-budget" role="tooltip" class="invisible absolute left-[calc(100%+0.6rem)] top-1/2 z-10 w-max max-w-[12rem] -translate-x-2 -translate-y-1/2 text-balance rounded-lg border border-slate-200 bg-white px-3 py-2 text-xs font-normal leading-relaxed text-slate-600 opacity-0 shadow-lg transition-all duration-200 before:absolute before:right-full before:top-1/2 before:h-2.5 before:w-2.5 before:-translate-y-1/2 before:translate-x-1/2 before:rotate-45 before:border-b before:border-l before:border-slate-200 before:bg-white before:content-[''] group-hover:visible group-hover:translate-x-0 group-hover:opacity-100 group-focus-within:visible group-focus-within:translate-x-0 group-focus-within:opacity-100">Spending pauses when you reach this limit. You can raise it at any time.</span>
</span>--tip-color on the element or a parent.
Currently previewing #3b82f6.--tip-size. Every other dimension is in
em, so the whole thing scales together. Currently previewing 16px.transition or animation
shorthand. Staggered delays are relative, so they keep their rhythm.