Dropdown simple two columns
A bar whose menus open ten links in two columns.
Last updated
---
/**
* Dropdown simple two columns: A bar whose menus open ten links in two columns.
*
* @block header-navigation
* @order 3
*/
import { Book, BookOpen, Box, CirclePlay, Code, FileCode, Layers, LifeBuoy, Mic, Orbit, Sparkles } from '@lucide/astro'
import Navbar from '@/components/apogee/Navbar/Navbar.astro'
import NavLink from '@/components/apogee/NavLink/NavLink.astro'
import NavDropdown from '@/components/apogee/NavDropdown/NavDropdown.astro'
import Link from '@/components/apogee/Link/Link.astro'
import Button from '@/components/apogee/Button/Button.astro'
import FeaturedIcon from '@/components/apogee/FeaturedIcon/FeaturedIcon.astro'
import Badge from '@/components/apogee/Badge/Badge.astro'
import type { NavGroup, NavigationContent } from '@/components/apogee/sections/_shared/navigation.ts'
const icons = [Book, Sparkles, CirclePlay, FileCode, LifeBuoy, Code, Box, Mic, BookOpen, Layers]
const groups: NavGroup[] = [{ items: [
{ label: 'Blog', href: '#', description: 'The latest industry news and guides, written by our team.' },
{ label: 'Customer stories', href: '#', description: 'How teams use the product to grow faster.' },
{ label: 'Video tutorials', href: '#', description: 'Get up and running on new features with short guides.' },
{ label: 'Documentation', href: '#', description: 'In-depth articles on our tools and technologies.' },
{ label: 'Help and support', href: '#', description: 'Need help with something? Our team is here around the clock.' },
{ label: 'API reference', href: '#', description: 'Reference docs and helpful guides for our API.' },
{ label: 'Setup 101', href: '#', description: 'Get up and running fast with our starter guide.' },
{ label: 'Mic', href: '#', description: 'Interviews and talk about the industry and the latest tech.' },
{ label: 'University', href: '#', description: 'Free video courses and in-depth articles to master your craft.' },
{ label: 'Changelog', href: '#', description: 'The latest updates and releases from our team.' },
] }]
/** @composable */
interface Props extends NavigationContent {
/** The bar's fill: the page, a grey band or the brand colour. */
background?: 'page' | 'neutral-faded' | 'primary' | undefined
/** `dark` sets the bar in the dark theme on a light page. */
theme?: 'dark' | undefined
}
const {
brand = 'Example',
links = [
{ label: 'Products', groups },
{ label: 'Services', groups },
{ label: 'Pricing', href: '#' },
{ label: 'Resources', groups },
{ label: 'About', href: '#' },
],
primaryAction = { label: 'Sign up', href: '#' },
secondaryAction = { label: 'Log in', href: '#' },
background,
theme,
} = Astro.props
---
<Navbar background={background} data-theme={theme}>
<Link slot="brand" href="/" color="inherit" underline="none" class="inline-flex items-center gap-2 text-lg font-semibold"><FeaturedIcon theme="solid" color="primary" size="small"><Orbit /></FeaturedIcon>{brand}</Link>
{links.map((l) => 'groups' in l ? (
<NavDropdown label={l.label} width="40rem">
<ul class="list-none p-0 grid gap-0.5 p-2 md:grid-cols-2">
{l.groups.flatMap((g) => g.items).map((i, n) => {
const Icon = icons[n % icons.length]!
return (
<li>
<Link href={i.href} color="inherit" underline="none" class="flex gap-3 rounded-lg p-3 transition-colors hover:bg-neutral-faded">
<Icon class="mt-0.5 size-5 shrink-0 text-primary" aria-hidden="true" />
<span class="flex flex-col gap-1">
<span class="flex flex-wrap items-center gap-2 font-semibold">{i.label}{i.badge && <Badge size="small" color={i.badge === 'New' ? 'neutral' : 'positive'} variant="faded">{i.badge}</Badge>}</span>
{i.description && <span class="line-clamp-2 text-sm text-neutral-faded">{i.description}</span>}
</span>
</Link>
</li>
)})}
</ul>
</NavDropdown>
) : <NavLink href={l.href}>{l.label}</NavLink>)}
{secondaryAction && <Button slot="actions" href={secondaryAction.href} variant="outline" color="neutral" size="small">{secondaryAction.label}</Button>}
{primaryAction && <Button slot="actions" href={primaryAction.href} size="small">{primaryAction.label}</Button>}
</Navbar>
Show codeHide code
---
/**
* Dropdown simple two columns: A bar whose menus open ten links in two columns.
*
* @block header-navigation
* @order 3
*/
import { Book, BookOpen, Box, CirclePlay, Code, FileCode, Layers, LifeBuoy, Mic, Orbit, Sparkles } from '@lucide/astro'
import Navbar from '@/components/apogee/Navbar/Navbar.astro'
import NavLink from '@/components/apogee/NavLink/NavLink.astro'
import NavDropdown from '@/components/apogee/NavDropdown/NavDropdown.astro'
import Link from '@/components/apogee/Link/Link.astro'
import Button from '@/components/apogee/Button/Button.astro'
import FeaturedIcon from '@/components/apogee/FeaturedIcon/FeaturedIcon.astro'
import Badge from '@/components/apogee/Badge/Badge.astro'
import type { NavGroup, NavigationContent } from '@/components/apogee/sections/_shared/navigation.ts'
const icons = [Book, Sparkles, CirclePlay, FileCode, LifeBuoy, Code, Box, Mic, BookOpen, Layers]
const groups: NavGroup[] = [{ items: [
{ label: 'Blog', href: '#', description: 'The latest industry news and guides, written by our team.' },
{ label: 'Customer stories', href: '#', description: 'How teams use the product to grow faster.' },
{ label: 'Video tutorials', href: '#', description: 'Get up and running on new features with short guides.' },
{ label: 'Documentation', href: '#', description: 'In-depth articles on our tools and technologies.' },
{ label: 'Help and support', href: '#', description: 'Need help with something? Our team is here around the clock.' },
{ label: 'API reference', href: '#', description: 'Reference docs and helpful guides for our API.' },
{ label: 'Setup 101', href: '#', description: 'Get up and running fast with our starter guide.' },
{ label: 'Mic', href: '#', description: 'Interviews and talk about the industry and the latest tech.' },
{ label: 'University', href: '#', description: 'Free video courses and in-depth articles to master your craft.' },
{ label: 'Changelog', href: '#', description: 'The latest updates and releases from our team.' },
] }]
/** @composable */
interface Props extends NavigationContent {
/** The bar's fill: the page, a grey band or the brand colour. */
background?: 'page' | 'neutral-faded' | 'primary' | undefined
/** `dark` sets the bar in the dark theme on a light page. */
theme?: 'dark' | undefined
}
const {
brand = 'Example',
links = [
{ label: 'Products', groups },
{ label: 'Services', groups },
{ label: 'Pricing', href: '#' },
{ label: 'Resources', groups },
{ label: 'About', href: '#' },
],
primaryAction = { label: 'Sign up', href: '#' },
secondaryAction = { label: 'Log in', href: '#' },
background,
theme,
} = Astro.props
---
<Navbar background={background} data-theme={theme}>
<Link slot="brand" href="/" color="inherit" underline="none" class="inline-flex items-center gap-2 text-lg font-semibold"><FeaturedIcon theme="solid" color="primary" size="small"><Orbit /></FeaturedIcon>{brand}</Link>
{links.map((l) => 'groups' in l ? (
<NavDropdown label={l.label} width="40rem">
<ul class="list-none p-0 grid gap-0.5 p-2 md:grid-cols-2">
{l.groups.flatMap((g) => g.items).map((i, n) => {
const Icon = icons[n % icons.length]!
return (
<li>
<Link href={i.href} color="inherit" underline="none" class="flex gap-3 rounded-lg p-3 transition-colors hover:bg-neutral-faded">
<Icon class="mt-0.5 size-5 shrink-0 text-primary" aria-hidden="true" />
<span class="flex flex-col gap-1">
<span class="flex flex-wrap items-center gap-2 font-semibold">{i.label}{i.badge && <Badge size="small" color={i.badge === 'New' ? 'neutral' : 'positive'} variant="faded">{i.badge}</Badge>}</span>
{i.description && <span class="line-clamp-2 text-sm text-neutral-faded">{i.description}</span>}
</span>
</Link>
</li>
)})}
</ul>
</NavDropdown>
) : <NavLink href={l.href}>{l.label}</NavLink>)}
{secondaryAction && <Button slot="actions" href={secondaryAction.href} variant="outline" color="neutral" size="small">{secondaryAction.label}</Button>}
{primaryAction && <Button slot="actions" href={primaryAction.href} size="small">{primaryAction.label}</Button>}
</Navbar>Add
npx @ava-ui/apogee add header-navigation/dropdown-simple-two-columns
This copies the block to src/components/apogee/blocks/header-navigation/ with everything it uses: Badge, Button, FeaturedIcon, Link, NavDropdown, NavLink, Navbar. Every piece of copy is a prop, with the sample copy as its default. Pass yours, or null to hide a part; see copy is props.
Accessibility
- Each menu is a button with a native popover: Esc or a click outside closes it and focus returns to the button. On phones the menus are rows that expand inside the menu. No JS is needed for either.
Related
NavbarA responsive site header that collapses its links into a mobile panel below the md breakpoint.
NavDropdownA Navbar item that opens a panel of links; a popover under the button or across the header on desktop, a row that expands in the phone menu.
NavLinkA navigation link that auto-detects and styles the current route, with prefix matching, external links and a collapsible NavGroup.