A responsive sidebar layout with desktop collapse and mobile toggle support.
A fixed sidebar on the left with a scrollable main content area.
<div>
<!-- Sidebar -->
<aside class="fixed top-0 left-0 h-screen w-64 flex flex-col
bg-white dark:bg-gray-900
border-r border-gray-200 dark:border-gray-800">
<!-- Logo -->
<div class="flex items-center gap-2 h-16 px-4 shrink-0
border-b border-gray-200 dark:border-gray-800">
<x-ui::icon name="bolt" variant="solid" class="text-primary-500 size-5 shrink-0" />
<span class="font-semibold text-gray-900 dark:text-white">App Name</span>
</div>
<!-- Nav -->
<nav class="flex-1 overflow-y-auto p-3">
<x-ui::navlist>
<x-ui::navlist-item href="#" icon="home">Home</x-ui::navlist-item>
<x-ui::navlist-item href="#" icon="chart-bar">Analytics</x-ui::navlist-item>
<x-ui::navlist-item href="#" icon="users">Users</x-ui::navlist-item>
<x-ui::navlist-item href="#" icon="cog-6-tooth">Settings</x-ui::navlist-item>
</x-ui::navlist>
</nav>
</aside>
<!-- Content -->
<div class="lg:pl-64 min-h-screen">
<header class="sticky top-0 z-40 flex items-center h-16 px-6
bg-white dark:bg-gray-900
border-b border-gray-200 dark:border-gray-800">
<h1 class="font-semibold text-gray-900 dark:text-white">Page Title</h1>
</header>
<main class="p-6">
{{ $slot }}
</main>
</div>
</div>
Add a toggle button at the bottom of the sidebar to collapse it to icon-only mode on desktop.
<div x-data="{ collapsed: false }">
<!-- Sidebar -->
<aside
class="fixed top-0 left-0 h-screen flex flex-col overflow-hidden
bg-white dark:bg-gray-900
border-r border-gray-200 dark:border-gray-800
transition-all duration-300 ease-in-out"
:class="collapsed ? 'w-16' : 'w-64'"
>
<!-- Logo -->
<div class="flex items-center h-16 px-4 shrink-0
border-b border-gray-200 dark:border-gray-800 overflow-hidden">
<x-ui::icon name="bolt" variant="solid" class="text-primary-500 size-5 shrink-0" />
<span x-show="!collapsed" x-collapse.horizontal
class="ml-2 font-semibold text-gray-900 dark:text-white whitespace-nowrap">
App Name
</span>
</div>
<!-- Nav -->
<nav class="flex-1 overflow-y-auto p-2">
<x-ui::navlist>
<x-ui::navlist-item href="#" icon="home">
<span x-show="!collapsed" x-transition:leave="transition-opacity duration-100"
x-transition:leave-end="opacity-0">Home</span>
</x-ui::navlist-item>
<x-ui::navlist-item href="#" icon="chart-bar">
<span x-show="!collapsed" x-transition:leave="transition-opacity duration-100"
x-transition:leave-end="opacity-0">Analytics</span>
</x-ui::navlist-item>
<x-ui::navlist-item href="#" icon="users">
<span x-show="!collapsed" x-transition:leave="transition-opacity duration-100"
x-transition:leave-end="opacity-0">Users</span>
</x-ui::navlist-item>
<x-ui::navlist-item href="#" icon="cog-6-tooth">
<span x-show="!collapsed" x-transition:leave="transition-opacity duration-100"
x-transition:leave-end="opacity-0">Settings</span>
</x-ui::navlist-item>
</x-ui::navlist>
</nav>
<!-- Collapse Toggle -->
<button
@click="collapsed = !collapsed"
class="hidden lg:flex items-center justify-center h-12 shrink-0
border-t border-gray-200 dark:border-gray-800
text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 transition-colors"
>
<x-ui::icon name="chevron-left" size="sm"
class="transition-transform duration-300"
:class="collapsed ? 'rotate-180' : ''" />
</button>
</aside>
<!-- Content -->
<div class="min-h-screen transition-all duration-300" :class="collapsed ? 'lg:pl-16' : 'lg:pl-64'">
<header class="sticky top-0 z-40 flex items-center h-16 px-6
bg-white dark:bg-gray-900
border-b border-gray-200 dark:border-gray-800">
<h1 class="font-semibold text-gray-900 dark:text-white">Page Title</h1>
</header>
<main class="p-6">{{ $slot }}</main>
</div>
</div>
On mobile, the sidebar is hidden off-screen and revealed by a hamburger button. A dimmed overlay closes it on tap.
<div x-data="{ sidebarOpen: false }">
<!-- Mobile Overlay -->
<div
x-show="sidebarOpen"
x-transition.opacity
class="fixed inset-0 bg-black/30 z-40 lg:hidden"
@click="sidebarOpen = false"
></div>
<!-- Sidebar -->
<aside
class="fixed z-50 top-0 left-0 h-screen w-64 flex flex-col
bg-white dark:bg-gray-900
border-r border-gray-200 dark:border-gray-800
transition-transform duration-200 ease-in-out
lg:translate-x-0"
:class="sidebarOpen ? 'translate-x-0' : '-translate-x-full'"
>
<!-- Logo + Close (mobile) -->
<div class="flex items-center justify-between h-16 px-4 shrink-0
border-b border-gray-200 dark:border-gray-800">
<div class="flex items-center gap-2">
<x-ui::icon name="bolt" variant="solid" class="text-primary-500 size-5" />
<span class="font-semibold text-gray-900 dark:text-white">App Name</span>
</div>
<button @click="sidebarOpen = false"
class="lg:hidden p-1 rounded text-gray-400 hover:text-gray-600 dark:hover:text-gray-200">
<x-ui::icon name="x-mark" size="sm" />
</button>
</div>
<!-- Nav -->
<nav class="flex-1 overflow-y-auto p-3">
<x-ui::navlist>
<x-ui::navlist-item href="#" icon="home">Home</x-ui::navlist-item>
<x-ui::navlist-item href="#" icon="chart-bar">Analytics</x-ui::navlist-item>
<x-ui::navlist-item href="#" icon="users">Users</x-ui::navlist-item>
<x-ui::navlist-item href="#" icon="cog-6-tooth">Settings</x-ui::navlist-item>
</x-ui::navlist>
</nav>
</aside>
<!-- Content -->
<div class="lg:pl-64 min-h-screen">
<header class="sticky top-0 z-40 flex items-center gap-3 h-16 px-4
bg-white dark:bg-gray-900
border-b border-gray-200 dark:border-gray-800">
<!-- Hamburger (mobile only) -->
<button @click="sidebarOpen = true"
class="lg:hidden p-1.5 rounded-md text-gray-500 hover:bg-gray-100 dark:hover:bg-gray-800">
<x-ui::icon name="bars-3" />
</button>
<h1 class="font-semibold text-gray-900 dark:text-white">Page Title</h1>
</header>
<main class="p-6">{{ $slot }}</main>
</div>
</div>
Complete ready-to-use sidebar layout combining collapse on desktop and hamburger toggle on mobile.
<div x-data="{ sidebarOpen: false, collapsed: false }">
<!-- Mobile Overlay -->
<div
x-show="sidebarOpen"
x-transition.opacity
class="fixed inset-0 bg-black/30 z-40 lg:hidden"
@click="sidebarOpen = false"
></div>
<!-- Sidebar -->
<aside
class="fixed z-50 top-0 left-0 h-screen flex flex-col overflow-hidden
bg-white dark:bg-gray-900
border-r border-gray-200 dark:border-gray-800
transition-all duration-300 ease-in-out
lg:translate-x-0"
:class="[
collapsed ? 'w-16' : 'w-64',
sidebarOpen ? 'translate-x-0' : '-translate-x-full',
]"
>
<!-- Logo -->
<div class="flex items-center h-16 px-4 shrink-0
border-b border-gray-200 dark:border-gray-800 overflow-hidden">
<x-ui::icon name="bolt" variant="solid" class="text-primary-500 size-5 shrink-0" />
<span x-show="!collapsed" x-collapse.horizontal
class="ml-2 font-semibold text-gray-900 dark:text-white whitespace-nowrap">
App Name
</span>
<button @click="sidebarOpen = false"
class="lg:hidden ml-auto p-1 rounded text-gray-400 hover:text-gray-600 dark:hover:text-gray-200">
<x-ui::icon name="x-mark" size="sm" />
</button>
</div>
<!-- Nav -->
<nav class="flex-1 overflow-y-auto p-2">
<x-ui::navlist>
<x-ui::navlist-item href="#" icon="home">
<span x-show="!collapsed" x-transition:leave="transition-opacity duration-100"
x-transition:leave-end="opacity-0">Home</span>
</x-ui::navlist-item>
<x-ui::navlist-item href="#" icon="chart-bar">
<span x-show="!collapsed" x-transition:leave="transition-opacity duration-100"
x-transition:leave-end="opacity-0">Analytics</span>
</x-ui::navlist-item>
<x-ui::navlist-item href="#" icon="users">
<span x-show="!collapsed" x-transition:leave="transition-opacity duration-100"
x-transition:leave-end="opacity-0">Users</span>
</x-ui::navlist-item>
<x-ui::navlist-item href="#" icon="cog-6-tooth">
<span x-show="!collapsed" x-transition:leave="transition-opacity duration-100"
x-transition:leave-end="opacity-0">Settings</span>
</x-ui::navlist-item>
</x-ui::navlist>
</nav>
<!-- Collapse Toggle (desktop only) -->
<button
@click="collapsed = !collapsed"
class="hidden lg:flex items-center justify-center h-12 shrink-0
border-t border-gray-200 dark:border-gray-800
text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 transition-colors"
>
<x-ui::icon name="chevron-left" size="sm"
class="transition-transform duration-300"
:class="collapsed ? 'rotate-180' : ''" />
</button>
</aside>
<!-- Content Wrapper -->
<div class="min-h-screen transition-all duration-300"
:class="collapsed ? 'lg:pl-16' : 'lg:pl-64'">
<!-- Header -->
<header class="sticky top-0 z-40 flex items-center gap-3 h-16 px-4
bg-white dark:bg-gray-900
border-b border-gray-200 dark:border-gray-800">
<!-- Hamburger (mobile only) -->
<button
@click="sidebarOpen = true"
class="lg:hidden p-1.5 rounded-md text-gray-500
hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors"
>
<x-ui::icon name="bars-3" />
</button>
<h1 class="font-semibold text-gray-900 dark:text-white">Page Title</h1>
</header>
<!-- Page Content -->
<main class="p-6">
{{ $slot }}
</main>
</div>
</div>
collapsed shrinks the sidebar to w-16 on desktop. Nav labels fade out via x-show + x-transition and the icon remains visible.
sidebarOpen slides the sidebar in on mobile via -translate-x-full / translate-x-0. The overlay closes it on tap.
lg:translate-x-0 keeps the sidebar permanently visible on large screens regardless of sidebarOpen.