AI CSS Animations

Context Menu Submenu Hover

A right-click style menu with shortcuts, where hovering Share slides a submenu out beside it. The submenu keeps a small hover bridge over the gap, so moving diagonally into it works.

Also known as: css submenu on hover, multi level dropdown css, context menu css.

HTML

<ul class="hfx-context-submenu">
  <li><a href="#"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="8" y="8" width="12" height="12" rx="2"/><path d="M16 8V5.5A1.5 1.5 0 0 0 14.5 4h-9A1.5 1.5 0 0 0 4 5.5v9A1.5 1.5 0 0 0 5.5 16H8"/></svg>Copy<kbd>&#8984;C</kbd></a></li>
  <li><a href="#"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="4" y="4" width="16" height="16" rx="2.5"/><path d="M12 8.5v7M8.5 12h7"/></svg>Duplicate<kbd>&#8984;D</kbd></a></li>
  <li class="hfx-context-submenu-parent">
    <a href="#" aria-haspopup="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3v12M7.5 7.5 12 3l4.5 4.5M5 13v5.5A1.5 1.5 0 0 0 6.5 20h11a1.5 1.5 0 0 0 1.5-1.5V13"/></svg>Share<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m9 6 6 6-6 6"/></svg></a>
    <ul class="hfx-context-submenu-sub">
      <li><a href="#">Email</a></li>
      <li><a href="#">Messages</a></li>
      <li><a href="#">Copy link</a></li>
    </ul>
  </li>
  <li><a href="#"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 7h16M10 11v6M14 11v6M6 7l1 12.5A1.5 1.5 0 0 0 8.5 21h7a1.5 1.5 0 0 0 1.5-1.5L18 7M9 7V4.5a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 .5.5V7"/></svg>Delete<kbd>&#9003;</kbd></a></li>
</ul>

CSS

.hfx-context-submenu {
  --c: var(--hfx-color, #3b82f6);
  font-size: var(--hfx-size, 16px);
  width: 11em;
  margin: 0 8.6em 0 0; /* room for the submenu in this preview */
  font-family: system-ui, sans-serif;
}
.hfx-context-submenu,
.hfx-context-submenu-sub {
  padding: 0.3em;
  list-style: none;
  border: 1px solid rgba(0, 0, 0, 0.08);
  border-radius: 0.7em;
  background: #fff;
  box-shadow: 0 0.8em 1.6em -0.6em rgba(15, 23, 42, 0.35);
  color: #1f2937;
}
.hfx-context-submenu a {
  display: flex;
  align-items: center;
  gap: 0.6em;
  padding: 0.45em 0.6em;
  border-radius: 0.45em;
  color: inherit;
  font-size: 0.9em;
  font-weight: 500;
  text-decoration: none;
  transition: background-color 0.15s ease, color 0.15s ease;
}
.hfx-context-submenu a svg {
  flex: none;
  width: 1.1em;
  height: 1.1em;
  color: #6b7280;
  transition: color 0.15s ease, transform 0.25s cubic-bezier(0.3, 0.7, 0.4, 1);
}
.hfx-context-submenu kbd,
.hfx-context-submenu a svg + svg { margin-left: auto; }
.hfx-context-submenu kbd {
  color: #9ca3af;
  font-family: inherit;
  font-size: 0.85em;
}
.hfx-context-submenu a:is(:hover, :focus-visible),
.hfx-context-submenu-parent:is(:hover, :focus-within) > a {
  background: color-mix(in srgb, var(--c) 13%, transparent);
  color: var(--c);
}
.hfx-context-submenu a:is(:hover, :focus-visible) svg,
.hfx-context-submenu-parent:is(:hover, :focus-within) > a svg { color: var(--c); }
.hfx-context-submenu-parent { position: relative; }
.hfx-context-submenu-sub {
  position: absolute;
  top: -0.35em;
  left: calc(100% + 0.5em);
  width: 8em;
  margin: 0;
  opacity: 0;
  visibility: hidden;
  transform: translateX(-0.5em) scale(0.97);
  transform-origin: 0 1em;
  transition: opacity 0.2s ease, transform 0.25s cubic-bezier(0.3, 0.7, 0.4, 1), visibility 0s 0.25s;
}
.hfx-context-submenu-sub::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  right: 100%;
  width: 0.8em;
}
.hfx-context-submenu-parent:is(:hover, :focus-within) > a svg + svg { transform: translateX(0.2em); }
.hfx-context-submenu-parent:is(:hover, :focus-within) .hfx-context-submenu-sub {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition-delay: 0s;
}

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

Customizing this snippet

  • Color: set --hfx-color on the element or a parent. Currently previewing #3b82f6.
  • Base size: set --hfx-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 hover effects

Sliding Pill Nav Hover Effect
Directional Underline Nav Hover Effect
Dot Indicator Nav Hover Effect
Vertical Nav Indicator Hover Effect