`) if you use page transitions or require a single root for layout.
Use the `header`, `body` and `footer` slots to customize the panel or the default slot if you don't want a scrollable body with padding.
```vue [DashboardPanelExample.vue]
```
> \[!NOTE]
>
> Most of the time, you will use the [`DashboardNavbar`](https://ui.nuxt.com/docs/components/dashboard-navbar) component in the `header` slot.
### Resizable
Use the `resizable` prop to make the panel resizable.
```vue
```
### Size
Use the `min-size`, `max-size` and `default-size` props to customize the size of the panel.
```vue
```
> \[!TIP]
> See: /docs/components/dashboard-group#props
>
> Sizes are calculated as percentages by default. You can change this using the `unit` prop on the `DashboardGroup` component.
## API
### Props
```ts
/**
* Props for the DashboardPanel component
*/
interface DashboardPanelProps {
ui?: { root?: ClassNameValue; body?: ClassNameValue; handle?: ClassNameValue; } | undefined;
/**
* The id of the panel.
*/
id?: string | undefined;
/**
* The minimum size of the panel.
* @default "15"
*/
minSize?: number | undefined;
/**
* The maximum size of the panel.
*/
maxSize?: number | undefined;
/**
* The default size of the panel.
*/
defaultSize?: number | undefined;
/**
* Whether to allow the user to resize the panel.
* @default "false"
*/
resizable?: boolean | undefined;
}
```
### Slots
```ts
/**
* Slots for the DashboardPanel component
*/
interface DashboardPanelSlots {
default(): any;
header(): any;
body(): any;
footer(): any;
resize-handle(): any;
}
```
## Theme
```ts [app.config.ts]
export default defineAppConfig({
ui: {
dashboardPanel: {
slots: {
root: 'relative flex flex-col min-w-0 min-h-svh lg:not-last:border-e lg:not-last:border-default shrink-0',
body: 'flex flex-col gap-4 sm:gap-6 flex-1 overflow-y-auto p-4 sm:p-6',
handle: ''
},
variants: {
size: {
true: {
root: 'w-full lg:w-(--width)'
},
false: {
root: 'flex-1'
}
}
}
}
}
})
```
## Changelog
See commit history for [component](https://github.com/nuxt/ui/commits/v4/src/runtime/components/DashboardPanel.vue) and [theme](https://github.com/nuxt/ui/commits/v4/src/theme/dashboard-panel.ts).
# DashboardResizeHandle
## Usage
The DashboardResizeHandle component is used by the [DashboardSidebar](https://ui.nuxt.com/docs/components/dashboard-sidebar) and [DashboardPanel](https://ui.nuxt.com/docs/components/dashboard-panel) components.
It is automatically displayed when the `resizable` prop is set, **you don't have to add it manually**.
## Examples
### Within `resize-handle` slot
Even though this component is automatically displayed when the `resizable` prop is set, you can use the `resize-handle` slot of the [DashboardSidebar](https://ui.nuxt.com/docs/components/dashboard-sidebar) and [DashboardPanel](https://ui.nuxt.com/docs/components/dashboard-panel) components to customize the handle.
```vue [layouts/dashboard.vue] {4-10}
```
```vue [pages/index.vue] {9-15}
```
> \[!NOTE]
>
> In this example, we add an `after` pseudo-element to display a vertical line on hover.
## API
### Props
```ts
/**
* Props for the DashboardResizeHandle component
*/
interface DashboardResizeHandleProps {
/**
* The element or component this component should render as.
*/
as?: any;
ui?: { base?: any; } | undefined;
}
```
### Slots
```ts
/**
* Slots for the DashboardResizeHandle component
*/
interface DashboardResizeHandleSlots {
default(): any;
}
```
## Theme
```ts [app.config.ts]
export default defineAppConfig({
ui: {
dashboardResizeHandle: {
base: 'hidden lg:block touch-none select-none cursor-ew-resize relative before:absolute before:inset-y-0 before:-left-1.5 before:-right-1.5 before:z-1'
}
}
})
```
## Changelog
See commit history for [component](https://github.com/nuxt/ui/commits/v4/src/runtime/components/DashboardResizeHandle.vue) and [theme](https://github.com/nuxt/ui/commits/v4/src/theme/dashboard-resize-handle.ts).
# DashboardSearch
## Usage
The DashboardSearch component extends the [CommandPalette](https://ui.nuxt.com/docs/components/command-palette) component, so you can pass any property such as `icon`, `placeholder`, etc.
Use it inside the default slot of the [DashboardGroup](https://ui.nuxt.com/docs/components/dashboard-group) component:
```vue [layouts/dashboard.vue] {3}
```
> \[!TIP]
>
> You can open the CommandPalette by pressing :kbd{value="meta"} :kbd{.ms-px value="K"}, by using the [DashboardSearchButton](https://ui.nuxt.com/docs/components/dashboard-search-button) component or by using a `v-model:open`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts"} directive.
### Shortcut
Use the `shortcut` prop to change the shortcut used in [defineShortcuts](https://ui.nuxt.com/docs/composables/define-shortcuts) to open the ContentSearch component. Defaults to `meta_k` ( :kbd{value="meta"} :kbd{value="K"} ).
```vue [app.vue] {4}
```
### Color Mode
By default, a group of commands will be added to the command palette so you can switch between light and dark mode. This will only take effect if the `colorMode` is not forced in a specific page which can be achieved through `definePageMeta`:
```vue [pages/index.vue]
```
You can disable this behavior by setting the `color-mode` prop to `false`:
```vue [app.vue] {4}
```
## API
### Props
```ts
/**
* Props for the DashboardSearch component
*/
interface DashboardSearchProps {
size?: "sm" | "md" | "xs" | "lg" | "xl" | undefined;
/**
* Display a close button in the input (useful when inside a Modal for example).
* `{ size: 'md', color: 'neutral', variant: 'ghost' }`{lang="ts-type"}
* @default "true"
*/
close?: boolean | Omit
| undefined;
/**
* Configure the input or hide it with `false`.
* `{ fixed: true }`{lang="ts-type"}
*/
input?: boolean | Omit, "modelValue" | "defaultValue"> | undefined;
/**
* Keyboard shortcut to open the search (used by [`defineShortcuts`](https://ui.nuxt.com/docs/composables/define-shortcuts))
* @default "\"meta_k\""
*/
shortcut?: string | undefined;
/**
* Options for [useFuse](https://vueuse.org/integrations/useFuse) passed to the [CommandPalette](https://ui.nuxt.com/docs/components/command-palette).
*/
fuse?: UseFuseOptions | undefined;
/**
* Delay (in milliseconds) before the search term is passed to Fuse (debounced).
* Useful for large datasets where running fuzzy search on every keystroke is the bottleneck — the input stays responsive while Fuse only re-runs after typing settles.
* Set to `0` to disable.
* @default "100"
*/
searchDelay?: number | undefined;
/**
* When `true`, the theme command will be added to the groups.
* @default "true"
*/
colorMode?: boolean | undefined;
ui?: ({ modal?: ClassNameValue; input?: ClassNameValue; } & { root?: ClassNameValue; input?: ClassNameValue; close?: ClassNameValue; back?: ClassNameValue; content?: ClassNameValue; footer?: ClassNameValue; viewport?: ClassNameValue; group?: ClassNameValue; empty?: ClassNameValue; label?: ClassNameValue; item?: ClassNameValue; itemLeadingIcon?: ClassNameValue; itemLeadingAvatar?: ClassNameValue; itemLeadingAvatarSize?: ClassNameValue; itemLeadingChip?: ClassNameValue; itemLeadingChipSize?: ClassNameValue; itemTrailing?: ClassNameValue; itemTrailingIcon?: ClassNameValue; itemTrailingHighlightedIcon?: ClassNameValue; itemTrailingKbds?: ClassNameValue; itemTrailingKbdsSize?: ClassNameValue; itemWrapper?: ClassNameValue; itemLabel?: ClassNameValue; itemLabelBase?: ClassNameValue; itemLabelPrefix?: ClassNameValue; itemLabelSuffix?: ClassNameValue; itemDescription?: ClassNameValue; }) | undefined;
title?: string | undefined;
/**
* Animate the modal when opening or closing.
*/
transition?: boolean | undefined;
description?: string | undefined;
/**
* Render an overlay behind the modal.
*/
overlay?: boolean | undefined;
/**
* The content of the modal.
*/
content?: (Omit & Partial>) | undefined;
/**
* When `false`, the modal will not close when clicking outside or pressing escape.
*/
dismissible?: boolean | undefined;
/**
* When `true`, the modal will take up the full screen.
* @default "false"
*/
fullscreen?: boolean | undefined;
/**
* The modality of the dialog When set to `true`,
* interaction with outside elements will be disabled and only dialog content will be visible to screen readers.
*/
modal?: boolean | undefined;
/**
* Render the modal in a portal.
*/
portal?: string | boolean | HTMLElement | undefined;
/**
* The icon displayed in the input.
*/
icon?: any;
/**
* Automatically focus the input when component is mounted.
*/
autofocus?: boolean | undefined;
/**
* When `true`, prevents the user from interacting with listbox
*/
disabled?: boolean | undefined;
/**
* The icon displayed on the right side of the input.
*/
trailingIcon?: any;
/**
* When `true`, the loading icon will be displayed.
*/
loading?: boolean | undefined;
/**
* The icon when the `loading` prop is `true`.
*/
loadingIcon?: any;
/**
* The icon displayed when an item is selected.
*/
selectedIcon?: any;
/**
* The icon displayed when an item has children.
*/
childrenIcon?: any;
/**
* The placeholder text for the input.
*/
placeholder?: string | undefined;
/**
* The icon displayed in the close button.
*/
closeIcon?: any;
/**
* Display a button to navigate back in history.
* `{ size: 'md', color: 'neutral', variant: 'link' }`{lang="ts-type"}
*/
back?: boolean | Omit | undefined;
/**
* The icon displayed in the back button.
*/
backIcon?: any;
/**
* When `true`, hover over item will trigger highlight
*/
highlightOnHover?: boolean | undefined;
/**
* The key used to get the label from the item.
*/
labelKey?: string | undefined;
/**
* The key used to get the description from the item.
*/
descriptionKey?: string | undefined;
/**
* Whether to preserve the order of groups as defined in the `groups` prop when filtering.
* When `false`, groups will appear based on item matches.
*/
preserveGroupOrder?: boolean | undefined;
/**
* Enable virtualization for large lists.
* Note: when enabled, all groups are flattened into a single list due to a limitation of Reka UI (https://github.com/unovue/reka-ui/issues/1885).
*/
virtualize?: boolean | { overscan?: number | undefined; estimateSize?: number | ((index: number) => number) | undefined; } | undefined;
groups?: CommandPaletteGroup[] | undefined;
/**
* @default "false"
*/
open?: boolean | undefined;
/**
* @default "\"\""
*/
searchTerm?: string | undefined;
}
```
### Slots
```ts
/**
* Slots for the DashboardSearch component
*/
interface DashboardSearchSlots {
empty(): any;
footer(): any;
back(): any;
close(): any;
item(): any;
item-leading(): any;
item-label(): any;
item-description(): any;
item-trailing(): any;
group-label(): any;
content(): any;
}
```
### Emits
```ts
/**
* Emitted events for the DashboardSearch component
*/
interface DashboardSearchEmits {
update:open: (payload: [value: boolean]) => void;
update:searchTerm: (payload: [value: string]) => void;
}
```
### Expose
When accessing the component via a template ref, you can use the following:
| Name | Type |
| --------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `commandPaletteRef`{.language-ts-type.shiki.shiki-themes.material-theme-lighter.material-theme.material-theme-palenight lang="ts-type"} | `Ref | null>`{.language-ts-type.shiki.shiki-themes.material-theme-lighter.material-theme.material-theme-palenight lang="ts-type"} |
## Theme
```ts [app.config.ts]
export default defineAppConfig({
ui: {
dashboardSearch: {
slots: {
modal: '',
input: ''
},
variants: {
fullscreen: {
false: {
modal: 'sm:max-w-3xl h-full sm:h-[28rem]'
}
},
size: {
xs: {},
sm: {},
md: {},
lg: {},
xl: {}
}
},
defaultVariants: {
size: 'md'
}
}
}
})
```
## Changelog
See commit history for [component](https://github.com/nuxt/ui/commits/v4/src/runtime/components/DashboardSearch.vue) and [theme](https://github.com/nuxt/ui/commits/v4/src/theme/dashboard-search.ts).
# DashboardSearchButton
## Usage
The DashboardSearchButton component is used to open the [DashboardSearch](https://ui.nuxt.com/docs/components/dashboard-search) modal.
```vue
```
It extends the [Button](https://ui.nuxt.com/docs/components/button) component, so you can pass any property such as `color`, `variant`, `size`, etc.
```vue
```
> \[!NOTE]
> See: #collapsed
>
> The button defaults to `color="neutral"` and `variant="outline"` when not collapsed, `variant="ghost"` when collapsed.
### Collapsed
Use the `collapsed` prop to hide the button's label and [kbds](https://ui.nuxt.com/#kbds). Defaults to `false`.
```vue
```
> \[!TIP]
> See: /docs/components/dashboard-sidebar#slots
>
> When using the button in the **DashboardSidebar** component, use the `collapsed` slot prop directly.
### Kbds
Use the `kbds` prop to display keyboard keys in the button. Defaults to `['meta', 'K']`{.shiki,shiki-themes,material-theme-lighter,material-theme,material-theme-palenight lang="ts-type"} to match the default shortcut of the [DashboardSearch](https://ui.nuxt.com/docs/components/dashboard-search#shortcut) component.
```vue
```
## API
### Props
```ts
/**
* Props for the DashboardSearchButton component
*/
interface DashboardSearchButtonProps {
/**
* The icon displayed in the button.
*/
icon?: any;
/**
* The label displayed in the button.
*/
label?: string | undefined;
/**
* The color of the button.
* @default "\"neutral\""
*/
color?: "error" | "neutral" | "primary" | "secondary" | "success" | "info" | "warning" | undefined;
/**
* The variant of the button.
* Defaults to 'outline' when not collapsed, 'ghost' when collapsed.
*/
variant?: "solid" | "outline" | "soft" | "subtle" | "ghost" | "link" | undefined;
/**
* Whether the button is collapsed.
* @default "false"
*/
collapsed?: boolean | undefined;
/**
* Display a tooltip on the button when is collapsed with the button label.
* This has priority over the global `tooltip` prop.
* @default "false"
*/
tooltip?: boolean | TooltipProps | undefined;
/**
* The keyboard keys to display in the button.
* `{ variant: 'subtle' }`{lang="ts-type"}
* @default "[\"meta\", \"k\"]"
*/
kbds?: (string | undefined)[] | KbdProps[] | undefined;
ui?: ({ base?: ClassNameValue; label?: ClassNameValue; trailing?: ClassNameValue; } & { base?: ClassNameValue; label?: ClassNameValue; leadingIcon?: ClassNameValue; leadingAvatar?: ClassNameValue; leadingAvatarSize?: ClassNameValue; trailingIcon?: ClassNameValue; }) | undefined;
/**
* Class to apply when the link is exact active
*/
exactActiveClass?: string | undefined;
/**
* Pass the returned promise of `router.push()` to `document.startViewTransition()` if supported.
*/
viewTransition?: boolean | undefined;
autofocus?: Booleanish | undefined;
disabled?: boolean | undefined;
form?: string | undefined;
formaction?: string | undefined;
formenctype?: string | undefined;
formmethod?: string | undefined;
formnovalidate?: Booleanish | undefined;
formtarget?: string | undefined;
name?: string | undefined;
/**
* The type of the button when not a link.
*/
type?: "reset" | "submit" | "button" | undefined;
onClick?: ((event: MouseEvent) => void | Promise) | ((event: MouseEvent) => void | Promise)[] | undefined;
/**
* The element or component this component should render as when not a link.
*/
as?: any;
activeColor?: "error" | "neutral" | "primary" | "secondary" | "success" | "info" | "warning" | undefined;
activeVariant?: "solid" | "outline" | "soft" | "subtle" | "ghost" | "link" | undefined;
size?: "xs" | "sm" | "md" | "lg" | "xl" | undefined;
/**
* Render the button with equal padding on all sides.
*/
square?: boolean | undefined;
/**
* Render the button full width.
*/
block?: boolean | undefined;
/**
* Set loading state automatically based on the `@click` promise state
*/
loadingAuto?: boolean | undefined;
/**
* Display an avatar on the left side.
*/
avatar?: AvatarProps | undefined;
/**
* When `true`, the icon will be displayed on the left side.
*/
leading?: boolean | undefined;
/**
* Display an icon on the left side.
*/
leadingIcon?: any;
/**
* When `true`, the icon will be displayed on the right side.
*/
trailing?: boolean | undefined;
/**
* Display an icon on the right side.
*/
trailingIcon?: any;
/**
* When `true`, the loading icon will be displayed.
*/
loading?: boolean | undefined;
/**
* The icon when the `loading` prop is `true`.
*/
loadingIcon?: any;
}
```
> \[!NOTE]
> See: https\://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attributes
>
> This component also supports all native `