Open demo

CSS code

HTML
<nav class="dock" aria-label="Apps">
  <ul>
    <li><a href="#" aria-current="page"><span aria-hidden="true">🏠</span><span class="dock-tip">Home</span><span class="dock-dot"><span class="dock-sr">(open)</span></span></a></li>
    <li><a href="#"><span aria-hidden="true">✉️</span><span class="dock-tip">Mail</span><span class="dock-dot"><span class="dock-sr">(open)</span></span></a></li>
    <li><a href="#"><span aria-hidden="true">🖼️</span><span class="dock-tip">Photos</span></a></li>
    <li><a href="#"><span aria-hidden="true">🎵</span><span class="dock-tip">Music</span></a></li>
    <li><a href="#"><span aria-hidden="true">⌨️</span><span class="dock-tip">Code</span><span class="dock-dot"><span class="dock-sr">(open)</span></span></a></li>
    <li><a href="#"><span aria-hidden="true">🖥️</span><span class="dock-tip">Terminal</span></a></li>
    <li><a href="#"><span aria-hidden="true">🗑️</span><span class="dock-tip">Trash</span></a></li>
  </ul>
</nav>
CSS
/* Floating dock: a list of app links. Each label is real text inside the link (its accessible name),
   shown as a tooltip on hover and on keyboard focus. */
.dock-sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
.dock{background:rgba(255,255,255,.16);border:1px solid rgba(255,255,255,.3);backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);border-radius:22px;padding:10px 14px;box-shadow:0 20px 44px rgba(0,0,0,.3)}
.dock ul{display:flex;align-items:flex-end;gap:10px;list-style:none;margin:0;padding:0}
.dock a{position:relative;width:54px;height:54px;border-radius:15px;font-size:1.6rem;text-decoration:none;background:rgba(255,255,255,.9);transition:transform .18s cubic-bezier(.34,1.56,.64,1);display:flex;align-items:center;justify-content:center}
.dock a[aria-current="page"]{box-shadow:0 0 0 2px #fff}
.dock-tip{position:absolute;top:-40px;left:50%;transform:translateX(-50%);background:rgba(10,12,24,.85);color:#fff;font-size:.68rem;font-weight:700;padding:4px 10px;border-radius:7px;opacity:0;transition:opacity .15s;white-space:nowrap;pointer-events:none}
.dock a:focus-visible{outline:3px solid #0f172a;outline-offset:2px;transform:translateY(-14px) scale(1.25)}
.dock a:focus-visible .dock-tip{opacity:1}
@media (hover:hover){.dock a:hover{transform:translateY(-14px) scale(1.25)}.dock a:hover .dock-tip{opacity:1}}
.dock-dot{position:absolute;bottom:-8px;left:50%;transform:translateX(-50%);width:4px;height:4px;border-radius:50%;background:#fff}
@media (max-width:520px){.dock{padding:8px 10px;border-radius:18px}.dock ul{gap:6px}.dock a{width:38px;height:38px;border-radius:11px;font-size:1.15rem}}
@media (prefers-reduced-motion:reduce){.dock a,.dock-tip{transition:none}}

Bootstrap 5 code

Requires: Bootstrap 5.3.8 CSS

HTML
<nav class="dock" aria-label="Apps">
  <ul class="nav">
    <li class="nav-item"><a class="nav-link active" href="#" aria-current="page"><span aria-hidden="true">🏠</span><span class="dock-tip">Home</span><span class="dock-dot"><span class="visually-hidden">(open)</span></span></a></li>
    <li class="nav-item"><a class="nav-link" href="#"><span aria-hidden="true">✉️</span><span class="dock-tip">Mail</span><span class="dock-dot"><span class="visually-hidden">(open)</span></span></a></li>
    <li class="nav-item"><a class="nav-link" href="#"><span aria-hidden="true">🖼️</span><span class="dock-tip">Photos</span></a></li>
    <li class="nav-item"><a class="nav-link" href="#"><span aria-hidden="true">🎵</span><span class="dock-tip">Music</span></a></li>
    <li class="nav-item"><a class="nav-link" href="#"><span aria-hidden="true">⌨️</span><span class="dock-tip">Code</span><span class="dock-dot"><span class="visually-hidden">(open)</span></span></a></li>
    <li class="nav-item"><a class="nav-link" href="#"><span aria-hidden="true">🖥️</span><span class="dock-tip">Terminal</span></a></li>
    <li class="nav-item"><a class="nav-link" href="#"><span aria-hidden="true">🗑️</span><span class="dock-tip">Trash</span></a></li>
  </ul>
</nav>
CSS
/* Bootstrap .nav of .nav-link tiles in a frosted dock. The label is real text inside each link (its accessible name),
   shown as a tooltip on hover and keyboard focus, so it rides the magnify transform with the icon. */
.dock{background:rgba(255,255,255,.16);border:1px solid rgba(255,255,255,.3);backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);border-radius:22px;padding:10px 14px;box-shadow:0 20px 44px rgba(0,0,0,.3)}
.dock .nav{--bs-nav-link-padding-x:0;--bs-nav-link-padding-y:0;--bs-nav-link-font-size:1.6rem;gap:10px;align-items:flex-end;flex-wrap:nowrap}
.dock .nav-link{position:relative;width:54px;height:54px;border-radius:15px;background:rgba(255,255,255,.9);transition:transform .18s cubic-bezier(.34,1.56,.64,1);display:flex;align-items:center;justify-content:center}
.dock .nav-link.active{box-shadow:0 0 0 2px #fff}
.dock-tip{position:absolute;top:-40px;left:50%;transform:translateX(-50%);background:rgba(10,12,24,.85);color:#fff;font-size:.68rem;font-weight:700;line-height:normal;padding:4px 10px;border-radius:7px;opacity:0;transition:opacity .15s;white-space:nowrap;pointer-events:none}
.dock .nav-link:focus-visible{outline:3px solid #0f172a;outline-offset:2px;box-shadow:none;transform:translateY(-14px) scale(1.25)}
.dock .nav-link:focus-visible .dock-tip{opacity:1}
@media (hover:hover){.dock .nav-link:hover{transform:translateY(-14px) scale(1.25)}.dock .nav-link:hover .dock-tip{opacity:1}}
.dock-dot{position:absolute;bottom:-8px;left:50%;transform:translateX(-50%);width:4px;height:4px;border-radius:50%;background:#fff}
@media (max-width:520px){.dock{padding:8px 10px;border-radius:18px}.dock .nav{gap:6px;--bs-nav-link-font-size:1.15rem}.dock .nav-link{width:38px;height:38px;border-radius:11px}}
@media (prefers-reduced-motion:reduce){.dock .nav-link,.dock-tip{transition:none}}

Tailwind 4 code

Requires: Tailwind CSS 4

HTML
<nav class="rounded-[22px] border border-white/30 bg-white/16 px-3.5 py-2.5 shadow-[0_20px_44px_rgba(0,0,0,.3)] backdrop-blur-[16px] max-[520px]:rounded-[18px] max-[520px]:px-2.5 max-[520px]:py-2" aria-label="Apps">
  <ul class="flex items-end gap-2.5 max-[520px]:gap-1.5">
    <li><a class="group relative flex size-[54px] items-center justify-center rounded-[15px] bg-white/90 text-[1.6rem] shadow-[0_0_0_2px_#fff] transition-transform duration-[180ms] ease-dock hover:-translate-y-3.5 hover:scale-125 focus-visible:-translate-y-3.5 focus-visible:scale-125 focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-[#0f172a] motion-reduce:transition-none max-[520px]:size-[38px] max-[520px]:rounded-[11px] max-[520px]:text-[1.15rem]" href="#" aria-current="page"><span aria-hidden="true">🏠</span><span class="pointer-events-none absolute -top-10 left-1/2 -translate-x-1/2 rounded-[7px] bg-[rgba(10,12,24,.85)] px-2.5 py-1 text-[.68rem] font-bold whitespace-nowrap text-white opacity-0 transition-opacity duration-150 group-hover:opacity-100 group-focus-visible:opacity-100 motion-reduce:transition-none">Home</span><span class="absolute -bottom-2 left-1/2 size-1 -translate-x-1/2 rounded-full bg-white"><span class="sr-only">(open)</span></span></a></li>
    <li><a class="group relative flex size-[54px] items-center justify-center rounded-[15px] bg-white/90 text-[1.6rem] transition-transform duration-[180ms] ease-dock hover:-translate-y-3.5 hover:scale-125 focus-visible:-translate-y-3.5 focus-visible:scale-125 focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-[#0f172a] motion-reduce:transition-none max-[520px]:size-[38px] max-[520px]:rounded-[11px] max-[520px]:text-[1.15rem]" href="#"><span aria-hidden="true">✉️</span><span class="pointer-events-none absolute -top-10 left-1/2 -translate-x-1/2 rounded-[7px] bg-[rgba(10,12,24,.85)] px-2.5 py-1 text-[.68rem] font-bold whitespace-nowrap text-white opacity-0 transition-opacity duration-150 group-hover:opacity-100 group-focus-visible:opacity-100 motion-reduce:transition-none">Mail</span><span class="absolute -bottom-2 left-1/2 size-1 -translate-x-1/2 rounded-full bg-white"><span class="sr-only">(open)</span></span></a></li>
    <li><a class="group relative flex size-[54px] items-center justify-center rounded-[15px] bg-white/90 text-[1.6rem] transition-transform duration-[180ms] ease-dock hover:-translate-y-3.5 hover:scale-125 focus-visible:-translate-y-3.5 focus-visible:scale-125 focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-[#0f172a] motion-reduce:transition-none max-[520px]:size-[38px] max-[520px]:rounded-[11px] max-[520px]:text-[1.15rem]" href="#"><span aria-hidden="true">🖼️</span><span class="pointer-events-none absolute -top-10 left-1/2 -translate-x-1/2 rounded-[7px] bg-[rgba(10,12,24,.85)] px-2.5 py-1 text-[.68rem] font-bold whitespace-nowrap text-white opacity-0 transition-opacity duration-150 group-hover:opacity-100 group-focus-visible:opacity-100 motion-reduce:transition-none">Photos</span></a></li>
    <li><a class="group relative flex size-[54px] items-center justify-center rounded-[15px] bg-white/90 text-[1.6rem] transition-transform duration-[180ms] ease-dock hover:-translate-y-3.5 hover:scale-125 focus-visible:-translate-y-3.5 focus-visible:scale-125 focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-[#0f172a] motion-reduce:transition-none max-[520px]:size-[38px] max-[520px]:rounded-[11px] max-[520px]:text-[1.15rem]" href="#"><span aria-hidden="true">🎵</span><span class="pointer-events-none absolute -top-10 left-1/2 -translate-x-1/2 rounded-[7px] bg-[rgba(10,12,24,.85)] px-2.5 py-1 text-[.68rem] font-bold whitespace-nowrap text-white opacity-0 transition-opacity duration-150 group-hover:opacity-100 group-focus-visible:opacity-100 motion-reduce:transition-none">Music</span></a></li>
    <li><a class="group relative flex size-[54px] items-center justify-center rounded-[15px] bg-white/90 text-[1.6rem] transition-transform duration-[180ms] ease-dock hover:-translate-y-3.5 hover:scale-125 focus-visible:-translate-y-3.5 focus-visible:scale-125 focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-[#0f172a] motion-reduce:transition-none max-[520px]:size-[38px] max-[520px]:rounded-[11px] max-[520px]:text-[1.15rem]" href="#"><span aria-hidden="true">⌨️</span><span class="pointer-events-none absolute -top-10 left-1/2 -translate-x-1/2 rounded-[7px] bg-[rgba(10,12,24,.85)] px-2.5 py-1 text-[.68rem] font-bold whitespace-nowrap text-white opacity-0 transition-opacity duration-150 group-hover:opacity-100 group-focus-visible:opacity-100 motion-reduce:transition-none">Code</span><span class="absolute -bottom-2 left-1/2 size-1 -translate-x-1/2 rounded-full bg-white"><span class="sr-only">(open)</span></span></a></li>
    <li><a class="group relative flex size-[54px] items-center justify-center rounded-[15px] bg-white/90 text-[1.6rem] transition-transform duration-[180ms] ease-dock hover:-translate-y-3.5 hover:scale-125 focus-visible:-translate-y-3.5 focus-visible:scale-125 focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-[#0f172a] motion-reduce:transition-none max-[520px]:size-[38px] max-[520px]:rounded-[11px] max-[520px]:text-[1.15rem]" href="#"><span aria-hidden="true">🖥️</span><span class="pointer-events-none absolute -top-10 left-1/2 -translate-x-1/2 rounded-[7px] bg-[rgba(10,12,24,.85)] px-2.5 py-1 text-[.68rem] font-bold whitespace-nowrap text-white opacity-0 transition-opacity duration-150 group-hover:opacity-100 group-focus-visible:opacity-100 motion-reduce:transition-none">Terminal</span></a></li>
    <li><a class="group relative flex size-[54px] items-center justify-center rounded-[15px] bg-white/90 text-[1.6rem] transition-transform duration-[180ms] ease-dock hover:-translate-y-3.5 hover:scale-125 focus-visible:-translate-y-3.5 focus-visible:scale-125 focus-visible:outline-3 focus-visible:outline-offset-2 focus-visible:outline-[#0f172a] motion-reduce:transition-none max-[520px]:size-[38px] max-[520px]:rounded-[11px] max-[520px]:text-[1.15rem]" href="#"><span aria-hidden="true">🗑️</span><span class="pointer-events-none absolute -top-10 left-1/2 -translate-x-1/2 rounded-[7px] bg-[rgba(10,12,24,.85)] px-2.5 py-1 text-[.68rem] font-bold whitespace-nowrap text-white opacity-0 transition-opacity duration-150 group-hover:opacity-100 group-focus-visible:opacity-100 motion-reduce:transition-none">Trash</span></a></li>
  </ul>
</nav>
CSS
@theme {
  --ease-dock: cubic-bezier(.34,1.56,.64,1);
}

About this set

A macOS-style dock of app shortcuts floating on a gradient. Seven rounded tiles (Home, Mail, Photos, Music, Code, Terminal and Trash) sit on a frosted glass shelf made with backdrop-filter. Pointing at a tile lifts and enlarges it with a springy easing curve and shows its name in a dark tooltip above; small dots under three tiles mark apps that are open, and the current one has a white ring. Use it as a playful launcher for a portfolio, a desktop-style web app or a demo page. Each tile is a link whose label is real text inside it, so the tooltip is also the accessible name and it appears on keyboard focus as well as on hover. The running dots carry visually hidden text so their meaning is not lost to screen readers. Hover effects only apply on devices that can hover, and below 520 pixels the tiles shrink from 54 to 38 pixels so the dock fits a phone. The Bootstrap version uses .nav and .nav-link with .visually-hidden, and the Tailwind version uses group-hover and group-focus-visible utilities.

What’s included

  • Frosted glass shelf with backdrop-filter
  • Tiles that lift and magnify on hover and keyboard focus
  • Tooltip labels that double as accessible names
  • Open-app dots with hidden text for screen readers
  • Smaller tiles below 520px so the dock fits a phone

Accessibility

The dock is a nav labelled Apps with a list of links, each named by its text label; the emoji icons are hidden from assistive technology and the open-app dots read as (open). The current app has aria-current="page" and a white ring. Keyboard focus lifts the tile, shows its label and draws a 3px dark outline, and all motion is removed under prefers-reduced-motion.

Customise it

Change the shelf tint and blur in .dock, the tile size in .dock a (plain CSS) or .dock .nav-link (Bootstrap), and the size-[54px], bg-white/16 and ease-dock values in Tailwind. The spring comes from the cubic-bezier(.34,1.56,.64,1) easing.