Side nav
Navegación de secciones tan ancha como su etiqueta más larga, con aria-current para la página actual.
Orders
32 orders this week · 4 to ship today
Instalación
$ pnpm dlx shadcn@latest add @ssntl/side-navUso
import { SideNav, SideNavItem } from "@/components/ui/side-nav"
<div className="grid grid-cols-[auto_minmax(0,1fr)] gap-6">
<SideNav aria-label="Tienda">
<SideNavItem href="/pedidos" current><Package /> Pedidos</SideNavItem>
<SideNavItem href="/clientes"><Users /> Clientes</SideNavItem>
</SideNav>
<main>…</main>
</div>- Del tamaño del contenido: la navegación es tan ancha como su etiqueta más larga (una columna auto); el contenido toma el resto.
- current pone aria-current="page"; el elemento activo también cambia de peso y fondo, no solo de color.
- Los elementos miden 44px con la etiqueta y un ícono opcional de 20px; usa etiquetas de una o dos palabras.
Código
import * as React from "react"
import { Slot } from "radix-ui"
import { cn } from "@/lib/utils"
// A vertical list of sections. It is as wide as its longest label, so the
// content beside it gets the room; never half the screen for three words.
// The current page is marked with aria-current, not color alone.
function SideNav({
className,
children,
...props
}: React.ComponentProps<"nav"> & { "aria-label": string }) {
return (
<nav
data-slot="side-nav"
className={cn("w-max max-w-full", className)}
{...props}
>
<ul className="grid gap-1">{children}</ul>
</nav>
)
}
function SideNavItem({
asChild = false,
current = false,
className,
...props
}: React.ComponentProps<"a"> & {
/** Render the child element (a framework Link, for example). */
asChild?: boolean
/** The page being shown: sets aria-current="page". */
current?: boolean
}) {
const Comp = asChild ? Slot.Root : "a"
return (
<li>
<Comp
data-slot="side-nav-item"
aria-current={current ? "page" : undefined}
className={cn(
"flex min-h-11 items-center gap-3 rounded-full px-4 text-label font-normal whitespace-nowrap text-muted-foreground",
"transition-[background-color,color] duration-(--duration-fast) ease-out hover:bg-secondary hover:text-foreground",
"focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring",
"aria-[current=page]:bg-secondary aria-[current=page]:font-medium aria-[current=page]:text-foreground",
"[&_svg]:size-5 [&_svg]:shrink-0",
className
)}
{...props}
/>
</li>
)
}
export { SideNav, SideNavItem }