A responsive and resizable panel to build multi-column layouts.
The DashboardPanel
component is the building block to create a multi-column layout.
<script setup lang="ts">
const links = [{
label: 'Home',
icon: 'i-heroicons-home'
}, {
label: 'Inbox',
icon: 'i-heroicons-inbox',
badge: '4'
}, {
label: 'Users',
icon: 'i-heroicons-user-group'
}, {
label: 'Settings',
icon: 'i-heroicons-cog-8-tooth',
children: [{
label: 'General'
}, {
label: 'Members'
}, {
label: 'Notifications'
}]
}]
</script>
<template>
<UDashboardPanel :width="300" :resizable="{ min: 200, max: 400 }">
<UDashboardNavbar>
<template #left>
<Logo class="w-auto h-5" />
</template>
</UDashboardNavbar>
<UDashboardSidebar>
<UDashboardSidebarLinks :links="links" />
</UDashboardSidebar>
</UDashboardPanel>
</template>
By default, the DashboardPanel
will take its content’s width. You can use the width
prop to set a fixed one.
<template>
<UDashboardPanel :width="250" />
</template>
You can use the grow
prop to make the DashboardPanel
take the remaining space. It can be useful for the last panel on the right side of the layout.
<template>
<UDashboardPanel grow />
</template>
When using the
grow
prop, the right border will be removed to make the layout look seamless.
You can use the resizable
prop to make the DashboardPanel
resizable and set the min
and max
values to limit the resizing.
<template>
<UDashboardPanel :width="300" :resizable="{ min: 200, max: 400 }" />
</template>
The width will be stored in a cookie to keep the layout consistent on refresh. You might want to use local storage instead by setting the storage
key to local
(this will only work if you’ve disabled ssr
if your nuxt.config.ts
).
<template>
<UDashboardPanel :width="300" :resizable="{ min: 200, max: 400, storage: 'local' }" />
</template>
We use the useId
composable to generate a unique id. When you have multiple resizable panels, it can be useful to set a custom one through the id
prop.
<template>
<UDashboardPanel id="inbox" :width="400" :resizable="{ min: 300, max: 500 }" />
</template>
A two or three column layout will not be very usable on mobile. You can use the collapsible
prop to transform the DashboardPanel
into a Slideover on mobile.
<template>
<UDashboardPanel collapsible />
</template>
In the useUIState
composable, we store a isDashboardSidebarSlideoverOpen
ref to control the state of the slideover on mobile. The DashboardPanel
will inject this to the DashboardNavbar inside to display a toggle button.
If you want to control the state of the slideover yourself or if you have multiple panels, you can pass a v-model
to the DashboardPanel
.
<script setup lang="ts">
const selected = ref(null)
const isOpen = computed({
get () {
return !!selected.value
},
set (value: boolean) {
if (!value) {
selected.value = null
}
}
})
</script>
<template>
<UDashboardPanel v-model="isOpen" collapsible />
</template>
It can be useful to change the icon of the toggle button as explained in DashboardNavbar.
When using the collapsible
prop, you can use the side
prop to set the side of the panel. The default value is left
.
<template>
<UDashboardPanel v-model="isOpen" collapsible side="right" />
</template>
The DashboardPanel
can be placed inside a DashboardLayout or a DashboardPage.
You can put a DashboardNavbar at the top followed by a DashboardSidebar, a DashboardToolbar or a DashboardPanelContent to display scrollable content for example.
<template>
<UDashboardLayout>
<UDashboardPanel :width="250" :resizable="{ min: 200, max: 300 }" collapsible>
<UDashboardNavbar />
<UDashboardSidebar />
</UDashboardPanel>
<slot />
</UDashboardLayout>
</template>
<template>
<UDashboardPage>
<UDashboardPanel id="inbox" :width="400" :resizable="{ min: 300, max: 500 }">
<UDashboardNavbar title="Inbox" />
<UDashboardPanelContent />
</UDashboardPanel>
<UDashboardPanel v-model="isOpen" collapsible grow side="right">
<UDashboardNavbar />
<UDashboardToolbar />
<UDashboardPanelContent />
</UDashboardPanel>
</UDashboardPage>
</template>
ui
- DeepPartial<{ wrapper: string; border: string; grow: string; collapsible: string; slideover: string; }> - Default: {}
id
- string - Default: undefined
side
- “left” | “right” - Default: "left"
resizable
- boolean | Record<string, any> - Default: false
width
- number - Default: undefined
breakpoint
- “sm” | “md” | “lg” | “xl” | “2xl” - Default: "lg"
modelValue
- boolean - Default: undefined
grow
- boolean - Default: false
collapsible
- boolean - Default: false
{
wrapper: 'flex-col items-stretch relative w-full',
border: 'border-b lg:border-b-0 lg:border-r border-gray-200 dark:border-gray-800 lg:w-[--width] flex-shrink-0',
grow: 'flex-1',
collapsible: 'hidden lg:flex',
slideover: 'lg:hidden'
}