Tooltip (CSS Only)
A fully CSS-driven tooltip with smooth opacity and scale/translate transitions. A single SVG icon supports three icon styles (info, question, alert) via data attribute path toggling. Horizontal and vertical position are controlled by data attributes, making it easy to swap alignment without touching CSS.
Code
<div data-css-tooltip-hover="" class="css-tooltip">
<span>You can hover me</span>
<div data-css-tooltip-icon="info" class="css-tooltip__icon">
<svg xmlns="http://www.w3.org/2000/svg" width="100%" viewbox="0 0 24 24" fill="none"><path d="M12 21C16.9706 21 21 16.9706 21 12C21 7.02944 16.9706 3 12 3C7.02944 3 3 7.02944 3 12C3 16.9706 7.02944 21 12 21Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M12 13.25V13C12 12.183 12.505 11.74 13.011 11.4C13.505 11.067 14 10.633 14 9.83301C14 8.72801 13.105 7.83301 12 7.83301C10.895 7.83301 10 8.72801 10 9.83301" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M11.999 16C11.861 16 11.749 16.112 11.75 16.25C11.75 16.388 11.862 16.5 12 16.5C12.138 16.5 12.25 16.388 12.25 16.25C12.25 16.112 12.138 16 11.999 16Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M12 13V7.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M11.999 16C11.861 16 11.749 16.112 11.75 16.25C11.75 16.388 11.862 16.5 12 16.5C12.138 16.5 12.25 16.388 12.25 16.25C12.25 16.112 12.138 16 11.999 16Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M11 15.5H13.3093" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M12.1588 15.5V11.25H11.0088" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M12.1001 8.24725C12.1001 8.2967 12.0854 8.34503 12.058 8.38615C12.0305 8.42726 11.9915 8.4593 11.9458 8.47822C11.9001 8.49714 11.8498 8.5021 11.8013 8.49245C11.7528 8.4828 11.7083 8.45899 11.6733 8.42403C11.6384 8.38907 11.6145 8.34452 11.6049 8.29603C11.5953 8.24753 11.6002 8.19726 11.6191 8.15158C11.638 8.1059 11.6701 8.06686 11.7112 8.03939C11.7523 8.01192 11.8007 7.99725 11.8501 7.99725" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M11.8501 7.99725C11.9164 7.99725 11.98 8.02359 12.0269 8.07048C12.0738 8.11736 12.1001 8.18095 12.1001 8.24725" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></svg>
<div data-css-tooltip-x="center" data-css-tooltip-y="top" class="css-tooltip__box">
<div class="css-tooltip__box-inner">
<div class="css-tooltip__card">
<div class="css-tooltip__card-title">
<h3 class="css-tooltip__card-h">CSS Only Tooltip</h3>
</div>
<div class="css-tooltip__card-text">
<p class="css-tooltip__card-p">Lorem ipsum dolor sit amet, consec adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore.</p>
</div>
</div>
<div class="css-tootlip__tip">
<svg xmlns="http://www.w3.org/2000/svg" width="100%" viewbox="0 0 124 30" fill="none"><path d="M103.284 3L121 3C122.657 3 124 1.65685 124 0L0 0C0 1.65685 1.34315 3 3 3L20.7157 3C26.0201 3 31.1071 5.10713 34.8579 8.85786L51.3934 25.3934C57.2513 31.2513 66.7487 31.2513 72.6066 25.3934L89.1421 8.85786C92.8929 5.10714 97.9799 3 103.284 3Z" fill="currentColor"></path></svg>
</div>
</div>
</div>
</div>
</div>.css-tooltip {
margin: 0;
}
.css-tooltip__icon {
vertical-align: sub;
cursor: pointer;
width: 1em;
height: 1em;
margin-left: .125em;
display: inline-block;
}
.css-tooltip__box {
flex-flow: column;
align-items: center;
padding-top: .5em;
padding-bottom: .5em;
display: flex;
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
transition: all 0.4s cubic-bezier(0.625, 0.05, 0, 1);
opacity: 0;
visibility: hidden;
}
[data-css-tooltip-hover]:hover .css-tooltip__box {
opacity: 1;
visibility: visible;
}
.css-tooltip__box-inner {
flex-flow: column;
align-items: center;
display: flex;
position: relative;
transition: transform 0.4s cubic-bezier(0.625, 0.05, 0, 1);
transform: translateY(1em) scale(0.9) rotate(0.001deg);
}
[data-css-tooltip-hover]:hover .css-tooltip__box-inner {
transform: translateY(0em) scale(1) rotate(0.001deg);
}
.css-tooltip__card {
grid-column-gap: .5em;
grid-row-gap: .5em;
color: #f4f4f4;
background-color: #201d1d;
border-radius: .75em;
flex-flow: column;
width: 21em;
max-width: calc(100vw - 1em);
margin-left: .5em;
margin-right: .5em;
padding: 1.5em;
display: flex;
}
.css-tootlip__tip {
width: 2.5em;
margin: -.0625em 1.25em;
display: flex;
position: relative;
}
.css-tooltip__card-text {
opacity: .75;
}
.css-tooltip__card-h {
font-size: 1.25em;
font-weight: 500;
line-height: inherit;
margin: 0;
}
.css-tooltip__card-p {
margin: 0;
}
/* Tooltip - Icon Types */
[data-css-tooltip-icon] > svg path:not(:first-child) {
display: none;
}
[data-css-tooltip-icon="question"] > svg path:nth-child(2),
[data-css-tooltip-icon="question"] > svg path:nth-child(3){
display: block;
}
[data-css-tooltip-icon="alert"] > svg path:nth-child(4),
[data-css-tooltip-icon="alert"] > svg path:nth-child(5){
display: block;
}
[data-css-tooltip-icon="info"] > svg path:nth-child(6),
[data-css-tooltip-icon="info"] > svg path:nth-child(7),
[data-css-tooltip-icon="info"] > svg path:nth-child(8),
[data-css-tooltip-icon="info"] > svg path:nth-child(9){
display: block;
}
/* Tooltip - Hover Element */
[data-css-tooltip-hover] {
position: relative;
cursor: pointer;
}
/* Tooltip - Bottom */
[data-css-tooltip-y="bottom"] {
top: 100%;
bottom: unset;
}
[data-css-tooltip-y="bottom"] .css-tooltip__card {
order: 2;
}
[data-css-tooltip-y="bottom"] .css-tootlip__tip {
transform: scaleY(-1);
}
[data-css-tooltip-y="bottom"] .css-tooltip__box-inner {
transform: translateY(-1em) scale(0.9) rotate(0.001deg);
}
/* Tooltip - Left */
[data-css-tooltip-x="left"] {
align-items: flex-start;
left: -2em;
transform: translateX(0%);
}
[data-css-tooltip-x="left"] .css-tooltip__box-inner {
align-items: flex-start;
}
/* Tooltip - Right */
[data-css-tooltip-x="right"] {
align-items: flex-end;
left: unset;
right: -2em;
transform: translateX(0%);
}
[data-css-tooltip-x="right"] .css-tooltip__box-inner {
align-items: flex-end;
}Attributes
| Name | Type | Default | Description |
|---|---|---|---|
| data-css-tooltip-hover | attribute | — | Defines the hover trigger element. Add to a wrapper that contains both the label text and the icon, or directly to the icon element. The :hover selector on this attribute drives the tooltip visibility. |
| data-css-tooltip-icon | attribute ("info" | "question" | "alert") | — | Controls which SVG paths are shown inside the icon element. The single embedded SVG contains all three icon variants; this attribute uses nth-child CSS selectors to display only the relevant paths. |
| data-css-tooltip-y | attribute ("top" | "bottom") | — | Sets the vertical position of the tooltip. "top" places it above the hover element (default). "bottom" flips the card order, inverts the tip arrow, and reverses the entry animation direction. |
| data-css-tooltip-x | attribute ("center" | "left" | "right") | — | Sets the horizontal alignment of the tooltip relative to the icon. "center" centers it over the icon. "left" aligns the card to the left edge. "right" aligns it to the right edge. |
Notes
- •Zero JavaScript — the entire interaction is driven by CSS :hover, opacity, visibility, and transform transitions.
- •The tip arrow SVG is a separate element flipped with scaleY(-1) when data-css-tooltip-y="bottom", keeping a single SVG for both directions.
- •max-width: calc(100vw - 1em) on .css-tooltip__card prevents the card from overflowing on narrow screens.
- •The entry animation uses a separate transition on .css-tooltip__box-inner (scale + translateY) while .css-tooltip__box handles opacity and visibility — this allows the two to use different easing values independently.
- •The icon type selector hides all paths except the circle outline by default, then shows only the nth-child paths for the selected icon style.
Guide
Hover trigger scope
Place [data-css-tooltip-hover] on a wrapper that contains both label text and the icon to make the entire element trigger the tooltip on hover. Or place it directly on the icon element for a tighter hit area.
Switching icon style
Change data-css-tooltip-icon on the icon element to switch between the three built-in styles. No SVG edits needed — CSS nth-child selectors handle which paths are visible.
<!-- Info icon -->
<div data-css-tooltip-icon="info" class="css-tooltip__icon">...</div>
<!-- Question mark icon -->
<div data-css-tooltip-icon="question" class="css-tooltip__icon">...</div>
<!-- Alert / exclamation icon -->
<div data-css-tooltip-icon="alert" class="css-tooltip__icon">...</div>Positioning
Combine data-css-tooltip-y and data-css-tooltip-x on the .css-tooltip__box element to position the tooltip in any of six configurations.
<!-- Above, centered -->
<div data-css-tooltip-x="center" data-css-tooltip-y="top" class="css-tooltip__box">
<!-- Below, left-aligned -->
<div data-css-tooltip-x="left" data-css-tooltip-y="bottom" class="css-tooltip__box">Custom card content
The .css-tooltip__card container accepts any HTML — swap the heading and paragraph for images, buttons, links, or any other elements.