№ 009

Mochi Nav

A kawaii tab bar of jelly buttons, with a kitten that hops over to the active one.

Version
1.0.0
Download
780 KB · 10 files
Added
Oct 26, 2026
Built with
HTML, CSS, JS
Needs
Google Fonts
Tags
tab bar, kawaii, jelly

Usage

Copy mochi-nav.css and mochi-nav.js (and assets/, if there is one) into your project, then:

  new MochiNav(element, {
    tabs: [{ label, img }],        // img: URL of a glossy round button (transparent PNG)
    active: 2,
    kitten: 'assets/kitten.png',
    sparkles: 'assets/sparkles.png',
    onChange(tab, index) {},
  })

A kawaii tab bar: the active jelly button grows and rises, the milky shell dips under it,
and a kitten hops over to rest her paws on top of it.

Source

/* Mochi nav — kawaii tab bar: milky pill, jelly buttons, a kitten who hops to the active tab. */

.mn {
  position: relative;
  width: 100%;
  max-width: 420px;
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
}

.mn-shell {
  position: absolute;
  left: 0;
  top: 0;
  overflow: visible;
  pointer-events: none;
  filter:
    drop-shadow(0 18px 26px rgba(150, 118, 214, 0.28))
    drop-shadow(0 4px 8px rgba(150, 118, 214, 0.18));
}

.mn-tabs {
  position: absolute;
  inset: 0;
}

.mn-tab {
  position: absolute;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(var(--mn-d) * 0.12);
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  font: inherit;
}

.mn-tab:focus-visible { outline: none; }
.mn-tab:focus-visible .mn-jelly { box-shadow: 0 0 0 3px rgba(255, 111, 115, 0.45); border-radius: 50%; }

.mn-jelly {
  display: block;
  width: var(--mn-d);
  height: var(--mn-d);
  transform-origin: 50% 70%;
  transition: transform 0.55s cubic-bezier(0.34, 1.56, 0.64, 1), filter 0.4s;
  filter: drop-shadow(0 4px 6px rgba(140, 110, 200, 0.22));
}

.mn-jelly img {
  width: 100%;
  height: 100%;
  display: block;
  pointer-events: none;
}

.mn-tab:hover .mn-jelly { transform: scale(1.07) translateY(-2px); }
.mn-tab:active .mn-jelly { transform: scale(0.93); }

.mn-tab.is-active .mn-jelly {
  transform: translateY(var(--mn-lift)) scale(var(--mn-grow));
  filter: drop-shadow(0 8px 12px rgba(255, 110, 120, 0.35));
}

.mn-label {
  color: #a493cc;
  font-size: calc(var(--mn-d) * 0.27);
  font-weight: 600;
  letter-spacing: 0.01em;
  line-height: 1;
  transition: color 0.3s, transform 0.45s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.mn-tab.is-active .mn-label {
  color: #ff6b70;
  transform: translateY(calc(var(--mn-d) * 0.06));
}

.mn-kitten {
  position: absolute;
  left: 0;
  top: 0;
  pointer-events: none;
  will-change: transform;
  filter: drop-shadow(0 6px 8px rgba(150, 110, 200, 0.22));
}

.mn-cat {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* by her right ear */
.mn-sparkles {
  position: absolute;
  left: 92%;
  top: -8%;
  width: 30%;
  transform-origin: 30% 70%;
  will-change: transform, opacity;
}

@media (prefers-reduced-motion: reduce) {
  .mn-jelly, .mn-label { transition: none; }
}
All 10 files in the zip
  • assets/discover.png
  • assets/friends.png
  • assets/home.png
  • assets/inbox.png
  • assets/kitten.png
  • assets/me.png
  • assets/sparkles.png
  • index.html
  • mochi-nav.css
  • mochi-nav.js