AI CSS Animations

Bar Chart Tooltip

A weekly bar chart that shows each day's value in a tooltip above the bar you hover while the other bars dim. With no bar hovered, the highlighted day keeps its tooltip, using :has().

Also known as: chart tooltip css, data point tooltip, graph hover value.

HTML

<span class="tip-bar-chart">
  <span class="tip-bar-chart-bar" tabindex="0" role="img" aria-label="Monday: 1,120 visits" data-day="M" style="--v: 45%"><span class="tip-bar-chart-tip" role="tooltip" aria-hidden="true">Mon <b>1,120</b></span></span>
  <span class="tip-bar-chart-bar" tabindex="0" role="img" aria-label="Tuesday: 1,540 visits" data-day="T" style="--v: 62%"><span class="tip-bar-chart-tip" role="tooltip" aria-hidden="true">Tue <b>1,540</b></span></span>
  <span class="tip-bar-chart-bar" tabindex="0" role="img" aria-label="Wednesday: 950 visits" data-day="W" style="--v: 38%"><span class="tip-bar-chart-tip" role="tooltip" aria-hidden="true">Wed <b>950</b></span></span>
  <span class="tip-bar-chart-bar" tabindex="0" role="img" aria-label="Thursday: 2,130 visits" data-day="T" style="--v: 85%"><span class="tip-bar-chart-tip" role="tooltip" aria-hidden="true">Thu <b>2,130</b></span></span>
  <span class="tip-bar-chart-bar" tabindex="0" role="img" aria-label="Friday: 1,760 visits" data-day="F" style="--v: 70%"><span class="tip-bar-chart-tip" role="tooltip" aria-hidden="true">Fri <b>1,760</b></span></span>
  <span class="tip-bar-chart-bar" tabindex="0" role="img" aria-label="Saturday: 1,300 visits" data-day="S" style="--v: 52%"><span class="tip-bar-chart-tip" role="tooltip" aria-hidden="true">Sat <b>1,300</b></span></span>
  <span class="tip-bar-chart-bar" tabindex="0" role="img" aria-label="Sunday: 760 visits" data-day="S" style="--v: 30%"><span class="tip-bar-chart-tip" role="tooltip" aria-hidden="true">Sun <b>760</b></span></span>
</span>

CSS

.tip-bar-chart {
  --c: var(--tip-color, #3b82f6);
  font-size: var(--tip-size, 16px);
  position: relative;
  display: inline-flex;
  align-items: flex-end;
  gap: 0.35em;
  margin-top: 1em; /* room for the tooltip in this preview */
  padding: 0 0.4em 1.5em;
  /* the baseline under the bars */
  background: linear-gradient(color-mix(in srgb, var(--c) 35%, transparent), color-mix(in srgb, var(--c) 35%, transparent)) 0 calc(100% - 1.5em) / 100% 1px no-repeat;
  font-family: system-ui, sans-serif;
}
/* the whole column is the hover target; the visible bar is ::before */
.tip-bar-chart-bar {
  position: relative;
  width: 1.8em;
  height: 7em;
  border-radius: 0.4em 0.4em 0 0;
  outline: none;
  transition: background-color 0.2s ease;
}
.tip-bar-chart-bar::before {
  content: "";
  position: absolute;
  right: 0.25em;
  bottom: 0;
  left: 0.25em;
  height: var(--v);
  border-radius: 0.3em 0.3em 0 0;
  background: var(--c);
  transition: opacity 0.25s ease, filter 0.25s ease;
}
.tip-bar-chart-bar::after {
  content: attr(data-day);
  position: absolute;
  top: calc(100% + 0.4em);
  left: 50%;
  color: color-mix(in srgb, currentColor 50%, transparent);
  font-size: 0.7em;
  font-weight: 600;
  transform: translateX(-50%);
}
.tip-bar-chart-bar:focus-visible { background: color-mix(in srgb, var(--c) 10%, transparent); }
.tip-bar-chart-bar:focus-visible::before { outline: 2px solid var(--c); outline-offset: 2px; }
.tip-bar-chart-tip {
  position: absolute;
  bottom: calc(var(--v) + 0.6em);
  left: 50%;
  z-index: 10;
  padding: 0.35em 0.6em;
  border-radius: 0.4em;
  background: color-mix(in srgb, var(--c) 14%, #0f172a);
  box-shadow: 0 0.4em 0.8em -0.3em rgb(0 0 0 / 0.5);
  color: rgb(255 255 255 / 0.65);
  font-size: 0.75em;
  font-weight: 500;
  line-height: 1.3;
  white-space: nowrap;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transform-origin: 50% 100%;
  transform: translate(-50%, 0.3em) scale(0.9);
  transition: opacity 0.15s ease, transform 0.25s cubic-bezier(0.3, 1.4, 0.5, 1), visibility 0.25s;
}
.tip-bar-chart-tip b {
  margin-left: 0.2em;
  color: #fff;
  font-weight: 700;
}
.tip-bar-chart-tip::before {
  content: "";
  position: absolute;
  top: 100%;
  left: 50%;
  width: 0.6em;
  height: 0.6em;
  background: inherit;
  transform: translate(-50%, -50%) rotate(45deg);
}
/* once the chart is hovered or focused, every bar dims except the active one */
.tip-bar-chart:hover .tip-bar-chart-bar::before,
.tip-bar-chart:focus-within .tip-bar-chart-bar::before { opacity: 0.35; }
.tip-bar-chart .tip-bar-chart-bar:hover::before,
.tip-bar-chart .tip-bar-chart-bar:focus-visible::before,
.tip-bar-chart:hover:not(:has(.tip-bar-chart-bar:hover, .tip-bar-chart-bar:focus-visible)) .tip-bar-chart-bar:nth-child(4)::before {
  opacity: 1;
  filter: saturate(1.3) brightness(1.05);
}
.tip-bar-chart-bar:hover .tip-bar-chart-tip,
.tip-bar-chart-bar:focus-visible .tip-bar-chart-tip,
.tip-bar-chart:hover:not(:has(.tip-bar-chart-bar:hover, .tip-bar-chart-bar:focus-visible)) .tip-bar-chart-bar:nth-child(4) .tip-bar-chart-tip {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, 0) scale(1);
}

@media (prefers-reduced-motion: reduce) {
  .tip-bar-chart, .tip-bar-chart *, .tip-bar-chart::before, .tip-bar-chart::after, .tip-bar-chart *::before, .tip-bar-chart *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

Customizing this snippet

  • Color: set --tip-color on the element or a parent. Currently previewing #3b82f6.
  • Base size: set --tip-size. Every other dimension is in em, so the whole thing scales together. Currently previewing 16px.
  • Speed: change the duration on the transition or animation shorthand. Staggered delays are relative, so they keep their rhythm.
  • Reduced motion: the rule at the end of the CSS turns the motion off for people who asked their OS for less of it. Keep it.

Similar tooltips