Dropdown Menu
A floating menu panel with icon, label and description items that highlight in brand color.
A floating menu panel with icon, label and description items that highlight in brand color. Compose it from the exported registry parts so local content and behaviour stay in the application while the visual contract stays token-driven.
newt-dropdownimport {
Dropdown,
DropdownContent,
DropdownDescription,
DropdownDivider,
DropdownIcon,
DropdownItem,
DropdownLabel,
} from "@/registry/bases/newt/ui/dropdown"
export default function DropdownDemo() {
return (
<Dropdown>
<DropdownItem active>
<DropdownIcon>{"⚡"}</DropdownIcon>
<DropdownContent>
<DropdownLabel>Option label</DropdownLabel>
<DropdownDescription>Option description</DropdownDescription>
</DropdownContent>
</DropdownItem>
<DropdownDivider />
<DropdownItem>
<DropdownIcon>{"⚙"}</DropdownIcon>
<DropdownContent>
<DropdownLabel>Another option</DropdownLabel>
<DropdownDescription>Description</DropdownDescription>
</DropdownContent>
</DropdownItem>
</Dropdown>
)
}<script setup lang="ts">
import {
Dropdown,
DropdownContent,
DropdownDescription,
DropdownDivider,
DropdownIcon,
DropdownItem,
DropdownLabel,
} from "~~/registry/bases/newt/ui/dropdown"
</script>
<template>
<Dropdown>
<DropdownItem active>
<DropdownIcon>⚡</DropdownIcon>
<DropdownContent>
<DropdownLabel>Option label</DropdownLabel>
<DropdownDescription>Option description</DropdownDescription>
</DropdownContent>
</DropdownItem>
<DropdownDivider />
<DropdownItem>
<DropdownIcon>⚙</DropdownIcon>
<DropdownContent>
<DropdownLabel>Another option</DropdownLabel>
<DropdownDescription>Description</DropdownDescription>
</DropdownContent>
</DropdownItem>
</Dropdown>
</template>Installation
pnpm dlx newtui@latest add dropdownnpx newtui@latest add dropdownyarn dlx newtui@latest add dropdownbunx newtui@latest add dropdownCopy the source into your project
import * as React from "react"
import { cn } from "@/lib/utils"
const Dropdown = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
role="menu"
className={cn(
"w-60 rounded-md border border-newt-border bg-[var(--newt-bg-floating)] p-1.5 text-newt-text-primary shadow-elevation-high",
className
)}
{...props}
/>
))
Dropdown.displayName = "Dropdown"
export interface DropdownItemProps extends React.HTMLAttributes<HTMLDivElement> {
/** Highlights the item as if hovered (e.g. keyboard focus / selected). */
active?: boolean
}
const DropdownItem = React.forwardRef<HTMLDivElement, DropdownItemProps>(
({ className, active = false, ...props }, ref) => (
<div
ref={ref}
role="menuitem"
tabIndex={-1}
data-active={active ? "" : undefined}
className={cn(
"group flex cursor-pointer items-center gap-2.5 rounded-sm px-2.5 py-2 transition-colors duration-fast ease-newt hover:bg-newt-brand data-[active]:bg-newt-brand",
className
)}
{...props}
/>
)
)
DropdownItem.displayName = "DropdownItem"
const DropdownIcon = React.forwardRef<
HTMLSpanElement,
React.HTMLAttributes<HTMLSpanElement>
>(({ className, ...props }, ref) => (
<span
ref={ref}
aria-hidden="true"
className={cn(
"w-5 shrink-0 text-center text-newt-text-muted group-hover:text-white group-data-[active]:text-white",
className
)}
{...props}
/>
))
DropdownIcon.displayName = "DropdownIcon"
const DropdownContent = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div ref={ref} className={cn("min-w-0", className)} {...props} />
))
DropdownContent.displayName = "DropdownContent"
const DropdownLabel = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div ref={ref} className={cn("text-sm font-medium", className)} {...props} />
))
DropdownLabel.displayName = "DropdownLabel"
const DropdownDescription = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn(
"text-xs text-newt-text-muted group-hover:text-white/75 group-data-[active]:text-white/75",
className
)}
{...props}
/>
))
DropdownDescription.displayName = "DropdownDescription"
const DropdownDivider = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
role="separator"
className={cn("mx-1.5 my-1 h-px bg-newt-border", className)}
{...props}
/>
))
DropdownDivider.displayName = "DropdownDivider"
export {
Dropdown,
DropdownItem,
DropdownIcon,
DropdownContent,
DropdownLabel,
DropdownDescription,
DropdownDivider,
}<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/lib/utils"
const props = defineProps<{ class?: HTMLAttributes["class"] }>()
</script>
<template>
<div
role="menu"
:class="
cn(
'w-60 rounded-md border border-newt-border bg-[var(--newt-bg-floating)] p-1.5 text-newt-text-primary shadow-elevation-high',
props.class
)
"
>
<slot />
</div>
</template><script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/lib/utils"
const props = defineProps<{
class?: HTMLAttributes["class"]
/** Highlights the item as if hovered (e.g. keyboard focus / selected). */
active?: boolean
}>()
</script>
<template>
<div
role="menuitem"
tabindex="-1"
:data-active="props.active ? '' : undefined"
:class="
cn(
'group flex cursor-pointer items-center gap-2.5 rounded-sm px-2.5 py-2 transition-colors duration-fast ease-newt hover:bg-newt-brand data-[active]:bg-newt-brand',
props.class
)
"
>
<slot />
</div>
</template><script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/lib/utils"
const props = defineProps<{ class?: HTMLAttributes["class"] }>()
</script>
<template>
<span
aria-hidden="true"
:class="
cn(
'w-5 shrink-0 text-center text-newt-text-muted group-hover:text-white group-data-[active]:text-white',
props.class
)
"
>
<slot />
</span>
</template><script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/lib/utils"
const props = defineProps<{ class?: HTMLAttributes["class"] }>()
</script>
<template>
<div :class="cn('min-w-0', props.class)">
<slot />
</div>
</template><script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/lib/utils"
const props = defineProps<{ class?: HTMLAttributes["class"] }>()
</script>
<template>
<div :class="cn('text-sm font-medium', props.class)">
<slot />
</div>
</template><script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/lib/utils"
const props = defineProps<{ class?: HTMLAttributes["class"] }>()
</script>
<template>
<div
:class="
cn(
'text-xs text-newt-text-muted group-hover:text-white/75 group-data-[active]:text-white/75',
props.class
)
"
>
<slot />
</div>
</template><script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { cn } from "@/lib/utils"
const props = defineProps<{ class?: HTMLAttributes["class"] }>()
</script>
<template>
<div
role="separator"
:class="cn('mx-1.5 my-1 h-px bg-newt-border', props.class)"
/>
</template>export { default as Dropdown } from "./Dropdown.vue"
export { default as DropdownItem } from "./DropdownItem.vue"
export { default as DropdownIcon } from "./DropdownIcon.vue"
export { default as DropdownContent } from "./DropdownContent.vue"
export { default as DropdownLabel } from "./DropdownLabel.vue"
export { default as DropdownDescription } from "./DropdownDescription.vue"
export { default as DropdownDivider } from "./DropdownDivider.vue"Update the import paths
The files import @/lib/utils and sibling components through the aliases in your components.json. Point them at wherever those live in your project.
Usage
import { Dropdown } from "@/components/ui/dropdown"
export function Example() {
return <Dropdown />
}<script setup lang="ts">
import { Dropdown, DropdownItem, DropdownIcon, DropdownContent, DropdownLabel, DropdownDescription, DropdownDivider } from "@/components/ui/dropdown"
</script>
<template>
<Dropdown />
</template>API reference
DropdownItem
active?boolean | undefined
Highlights the item as if hovered (e.g. keyboard focus / selected).
boolean | undefinedThe registry exports Dropdown, DropdownItem, DropdownIcon, DropdownContent, DropdownLabel, DropdownDescription, DropdownDivider. Parts without a table accept the native attributes for the element they render; React uses className, while Vue uses class and fallthrough attributes.
Accessibility
Connect the trigger and menu with aria-controls and aria-expanded, support arrow keys and Escape, and return focus to the trigger on close.
Tokens
Dropdown Menu reads its colours, radii and motion from the --newt-* tokens installed with the library. Override a token and every component that reads it follows, including this one — see the token layer. In the plain HTML and CSS distribution the same component is newt-dropdown.