Component

Mobile Tabs

Bottom mobile tab navigation bar with icons, labels, and a notification badge. Switches app screens within a phone-style frame. Built for native-feeling mobile web apps.

  • Component
  • Tailwind
  • HTML
  • MIT

Preview

Live component

Interactive preview
Open preview
9:41 100%
devsnips.dev/library/tailwind/components/tabs/mobile-tabs/
fluid · no fixed width 100%
No dependencies Production-ready

Install

Add to your project

terminal
npx devsnips add Tailwind/Components/Tabs/mobile-tabs
registry path: Tailwind/Components/Tabs/mobile-tabs

Source

Implementation

code.html
<div class="w-full max-w-sm mx-auto">
  <!-- App screen -->
  <div class="relative bg-gray-50 border border-gray-200 rounded-3xl overflow-hidden shadow-sm" style="min-height:520px">
    <!-- Top bar -->
    <div class="bg-white px-5 py-4 border-b border-gray-100 flex items-center justify-between">
      <h2 class="text-base font-semibold text-gray-900">Home</h2>
      <div class="w-9 h-9 rounded-full bg-gradient-to-br from-indigo-400 to-purple-500 flex items-center justify-center text-white text-sm font-semibold">S</div>
    </div>

    <!-- Panels -->
    <div class="p-5 pb-28">
      <div role="tabpanel" id="mob-panel-home" aria-labelledby="mob-tab-home" tabindex="0" class="focus:outline-none">
        <p class="text-xs font-medium text-indigo-600">Good morning, Sarah</p>
        <h3 class="mt-1 text-lg font-bold text-gray-900">Pick up where you left off</h3>
        <div class="mt-4 rounded-2xl bg-gradient-to-br from-indigo-500 to-purple-600 p-4 text-white">
          <p class="text-sm font-medium">Continue: Onboarding flow</p>
          <p class="mt-1 text-xs text-indigo-100">3 of 5 steps complete</p>
          <div class="mt-3 h-1.5 bg-white/30 rounded-full overflow-hidden"><div class="h-full bg-white rounded-full" style="width:60%"></div></div>
        </div>
        <div class="mt-4 grid grid-cols-2 gap-3">
          <div class="rounded-xl bg-white border border-gray-200 p-3"><p class="text-sm font-medium text-gray-900">Tasks</p><p class="text-xs text-gray-500">4 due today</p></div>
          <div class="rounded-xl bg-white border border-gray-200 p-3"><p class="text-sm font-medium text-gray-900">Messages</p><p class="text-xs text-gray-500">2 unread</p></div>
        </div>
      </div>
      <div role="tabpanel" id="mob-panel-search" aria-labelledby="mob-tab-search" tabindex="0" class="hidden focus:outline-none">
        <div class="flex items-center gap-2 bg-white border border-gray-200 rounded-xl px-3 py-2.5">
          <svg class="w-4 h-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/></svg>
          <input type="text" placeholder="Search people, files…" class="flex-1 bg-transparent text-sm outline-none">
        </div>
        <p class="mt-4 text-xs font-semibold text-gray-500 uppercase tracking-wide">Recent</p>
        <ul class="mt-2 space-y-1 text-sm text-gray-700"><li class="py-2 border-b border-gray-100">Design system tokens</li><li class="py-2 border-b border-gray-100">Q3 roadmap</li><li class="py-2">Sarah Mitchell</li></ul>
      </div>
      <div role="tabpanel" id="mob-panel-notifications" aria-labelledby="mob-tab-notifications" tabindex="0" class="hidden focus:outline-none">
        <h3 class="text-lg font-bold text-gray-900">Notifications</h3>
        <ul class="mt-3 space-y-2">
          <li class="flex gap-3 rounded-xl bg-white border border-gray-200 p-3"><span class="w-2 h-2 mt-1.5 rounded-full bg-indigo-500"></span><div><p class="text-sm font-medium text-gray-900">New comment on your task</p><p class="text-xs text-gray-500">2 min ago</p></div></li>
          <li class="flex gap-3 rounded-xl bg-white border border-gray-200 p-3"><span class="w-2 h-2 mt-1.5 rounded-full bg-gray-300"></span><div><p class="text-sm font-medium text-gray-900">Weekly digest ready</p><p class="text-xs text-gray-500">1h ago</p></div></li>
        </ul>
      </div>
      <div role="tabpanel" id="mob-panel-profile" aria-labelledby="mob-tab-profile" tabindex="0" class="hidden focus:outline-none">
        <div class="flex items-center gap-3">
          <div class="w-14 h-14 rounded-full bg-gradient-to-br from-indigo-400 to-purple-500 flex items-center justify-center text-white text-lg font-semibold">S</div>
          <div><p class="text-base font-semibold text-gray-900">Sarah Mitchell</p><p class="text-xs text-gray-500">sarah@acme.io</p></div>
        </div>
        <ul class="mt-5 divide-y divide-gray-100 text-sm">
          <li class="py-3 flex items-center justify-between"><span class="text-gray-700">Account settings</span><span class="text-gray-400">›</span></li>
          <li class="py-3 flex items-center justify-between"><span class="text-gray-700">Help & support</span><span class="text-gray-400">›</span></li>
          <li class="py-3 flex items-center justify-between"><span class="text-rose-600">Sign out</span><span class="text-gray-400">›</span></li>
        </ul>
      </div>
    </div>

    <!-- Bottom tab bar -->
    <nav class="absolute bottom-0 inset-x-0 bg-white/95 backdrop-blur border-t border-gray-200" aria-label="Primary">
      <div role="tablist" class="grid grid-cols-4">
        <button role="tab" id="mob-tab-home" aria-selected="true" aria-controls="mob-panel-home" tabindex="0"
          class="flex flex-col items-center gap-0.5 py-2.5 text-indigo-600 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-indigo-500">
          <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"/></svg>
          <span class="text-[10px] font-medium">Home</span>
        </button>
        <button role="tab" id="mob-tab-search" aria-selected="false" aria-controls="mob-panel-search" tabindex="-1"
          class="flex flex-col items-center gap-0.5 py-2.5 text-gray-400 hover:text-gray-600 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-indigo-500">
          <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"/></svg>
          <span class="text-[10px] font-medium">Search</span>
        </button>
        <button role="tab" id="mob-tab-notifications" aria-selected="false" aria-controls="mob-panel-notifications" tabindex="-1"
          class="relative flex flex-col items-center gap-0.5 py-2.5 text-gray-400 hover:text-gray-600 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-indigo-500">
          <span class="relative">
            <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"/></svg>
            <span class="absolute -top-0.5 -right-0.5 w-2 h-2 bg-rose-500 rounded-full ring-2 ring-white"></span>
          </span>
          <span class="text-[10px] font-medium">Alerts</span>
        </button>
        <button role="tab" id="mob-tab-profile" aria-selected="false" aria-controls="mob-panel-profile" tabindex="-1"
          class="flex flex-col items-center gap-0.5 py-2.5 text-gray-400 hover:text-gray-600 transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-indigo-500">
          <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"/></svg>
          <span class="text-[10px] font-medium">Profile</span>
        </button>
      </div>
    </nav>
  </div>
</div>

<script>
  (function () {
    var list = document.querySelector('[aria-label="Primary"]');
    if (!list) return;
    var tabs = Array.prototype.slice.call(list.querySelectorAll('[role="tab"]'));
    var panels = tabs.map(function (t) { return document.getElementById(t.getAttribute('aria-controls')); });
    function activate(tab) {
      tabs.forEach(function (t) {
        var s = t === tab;
        t.setAttribute('aria-selected', s); t.tabIndex = s ? 0 : -1;
        t.classList.toggle('text-indigo-600', s);
        t.classList.toggle('text-gray-400', !s);
        t.classList.toggle('hover:text-gray-600', !s);
      });
      panels.forEach(function (p) { if (p) p.classList.add('hidden'); });
      var panel = document.getElementById(tab.getAttribute('aria-controls'));
      if (panel) panel.classList.remove('hidden');
    }
    tabs.forEach(function (tab, i) {
      tab.addEventListener('click', function () { activate(tab); });
      tab.addEventListener('keydown', function (e) {
        var idx = null;
        if (e.key === 'ArrowRight') idx = (i + 1) % tabs.length;
        if (e.key === 'ArrowLeft') idx = (i - 1 + tabs.length) % tabs.length;
        if (idx !== null) { e.preventDefault(); tabs[idx].focus(); activate(tabs[idx]); }
      });
    });
  })();
</script>
112 lines UTF-8 · LF · Spaces: 2

AI-ready

Available to your agent.

This component is reachable through the DevSnips CLI, MCP server and Skills integrations — one registry, one resource path.

Resource path

devsnips://components/tabs/mobile-tabs

Continue browsing

View all