Link Group
The LinkGroup component renders an ordered collection of LinkItem entries using the Link component. It supports position-based variant assignment via an ordered slot system, flexible container semantics (div, ul, nav), and full delegation of per-item rendering, accessibility, and fallback behavior to Link.
import { LinkGroup } from "@/registry/rokkit200-ui/components/link-group/link-group";import type { LinkItem } from "@/registry/rokkit200-ui/components/link/link";
const items: LinkItem[] = [ { id: "1", label: "Get Started", destination: { type: "internal", href: "#" }, }, { id: "2", label: "Learn More", destination: { type: "internal", href: "#" }, }, { id: "3", label: "Contact Us", destination: { type: "internal", href: "#" }, },];
export default function LinkGroupDefaultDemo() { return ( <LinkGroup items={items} className="flex gap-2" linkClassName="w-1/3" /> );}import { LinkGroup } from "@/rokkit200-ui/components/link-group/link-group";<LinkGroup items={items} className="flex gap-2" linkClassName="w-1/3"/>Examples
Section titled “Examples”Single Variant
Section titled “Single Variant”When a single variant slot is provided, all items receive that variant.
import { LinkGroup } from "@/registry/rokkit200-ui/components/link-group/link-group";import type { LinkItem } from "@/registry/rokkit200-ui/components/link/link";
const items: LinkItem[] = [ { id: "1", label: "Get Started", destination: { type: "internal", href: "#" }, }, { id: "2", label: "Learn More", destination: { type: "internal", href: "#" }, }, { id: "3", label: "Contact Us", destination: { type: "internal", href: "#" }, },];
export default function LinkGroupSingleVariantDemo() { return ( <LinkGroup items={items} variantSlots={["secondary"]} className="flex gap-2" linkClassName="w-1/3" /> );}Two Variant Slots
Section titled “Two Variant Slots”The first item receives the first slot, all remaining items receive the second slot.
import { LinkGroup } from "@/registry/rokkit200-ui/components/link-group/link-group";import type { LinkItem } from "@/registry/rokkit200-ui/components/link/link";
const items: LinkItem[] = [ { id: "1", label: "Get Started", destination: { type: "internal", href: "#" }, }, { id: "2", label: "Learn More", destination: { type: "internal", href: "#" }, }, { id: "3", label: "Contact Us", destination: { type: "internal", href: "#" }, },];
export default function LinkGroupTwoVariantsDemo() { return ( <LinkGroup items={items} variantSlots={["primary", "secondary"]} className="flex gap-2" linkClassName="w-1/3" /> );}Three Variant Slots
Section titled “Three Variant Slots”The first item receives the first slot, the second item receives the second slot, and all remaining items receive the third slot.
import { LinkGroup } from "@/registry/rokkit200-ui/components/link-group/link-group";import type { LinkItem } from "@/registry/rokkit200-ui/components/link/link";
const items: LinkItem[] = [ { id: "1", label: "Get Started", destination: { type: "internal", href: "#" }, }, { id: "2", label: "Learn More", destination: { type: "internal", href: "#" }, }, { id: "3", label: "Contact Us", destination: { type: "internal", href: "#" }, },];
export default function LinkGroupThreeVariantsDemo() { return ( <LinkGroup items={items} variantSlots={["primary", "secondary", "outline"]} className="flex gap-2" linkClassName="w-1/3" /> );}Nav Container
Section titled “Nav Container”When as="nav" is used, the container renders as a <nav> element with aria-label from navLabel for accessible labeling.
import { LinkGroup } from "@/registry/rokkit200-ui/components/link-group/link-group";import type { LinkItem } from "@/registry/rokkit200-ui/components/link/link";
const items: LinkItem[] = [ { id: "1", label: "Home", destination: { type: "internal", href: "#" }, }, { id: "2", label: "About", destination: { type: "internal", href: "#" }, }, { id: "3", label: "Contact", destination: { type: "internal", href: "#" }, },];
export default function LinkGroupAsNavDemo() { return ( <LinkGroup items={items} as="nav" navLabel="Primary navigation" variantSlots={["primary", "secondary"]} className="flex gap-2 sm:flex-nowrap" linkClassName="w-1/3" /> );}List Container
Section titled “List Container”When as="ul" is used, each link is automatically wrapped in an <li> element for valid list markup.
import { LinkGroup } from "@/registry/rokkit200-ui/components/link-group/link-group";import type { LinkItem } from "@/registry/rokkit200-ui/components/link/link";
const items: LinkItem[] = [ { id: "1", label: "Home", destination: { type: "internal", href: "#" }, }, { id: "2", label: "About", destination: { type: "internal", href: "#" }, }, { id: "3", label: "Contact", destination: { type: "internal", href: "#" }, },];
export default function LinkGroupAsUlDemo() { return ( <LinkGroup items={items} as="ul" variantSlots={["outline"]} className="flex flex-col flex-wrap gap-y-2" linkClassName="w-full" /> );}Invalid Item Resilience
Section titled “Invalid Item Resilience”Invalid items are forwarded to Link, which renders them as a non-interactive <span> fallback. No items are silently dropped or hidden.
import { LinkGroup } from "@/registry/rokkit200-ui/components/link-group/link-group";import type { LinkItem } from "@/registry/rokkit200-ui/components/link/link";
const items: LinkItem[] = [ { id: "1", label: "Get Started", destination: { type: "internal", href: "#" }, }, { id: "2", label: "Unresolved Link", destination: { type: "invalid", reason: "Missing URL" }, }, { id: "3", label: "Contact Us", destination: { type: "internal", href: "#" }, },];
export default function LinkGroupInvalidItemDemo() { return ( <LinkGroup items={items} variantSlots={["primary", "secondary", "outline"]} className="flex gap-2" linkClassName="w-1/3" /> );}API Reference
Section titled “API Reference”| Prop | Type | Default | Description |
|---|---|---|---|
items | LinkItem[] | — | Ordered collection of normalized link items. All items render in authored order. |
variantSlots | VariantSlot[] | ["primary"] | Ordered variant emphasis array. Maps onto items by index position (see Variant Slot Resolution). |
as | "div" | "ul" | "nav" | "div" | Container element. Consumer chooses semantic wrapper based on block context. |
className | string | undefined | CSS classes applied to the container element. |
linkClassName | string | Partial<Record<VariantSlot, string>> | ((variant: VariantSlot, index: number) => string) | undefined | Optional classes applied to each rendered Link. Supports a single class string, variant-keyed object map, or resolver function. |
navLabel | string | undefined | aria-label for the container when as="nav". Required when using nav. |
Variant Slot Resolution
Section titled “Variant Slot Resolution”The variantSlots array assigns visual emphasis to items by position. The rules are deterministic and do not depend on item content:
- 1 slot: all items use
slots[0]. - 2 slots: index 0 uses
slots[0], index 1+ usesslots[1]. - 3+ slots: index 0 uses
slots[0], index 1 usesslots[1], index 2+ usesslots[2]. Extra slots beyond 3 are ignored. - Default (no slots provided): all items receive
"primary".
Container Semantics
Section titled “Container Semantics”as="div"— default, no implicit semantic meaning.as="ul"— eachLinkis wrapped in<li>for valid list markup.as="nav"— renders<nav>witharia-labelfromnavLabel. A dev warning is emitted whennavLabelis omitted.
Accessibility
Section titled “Accessibility”- Per-item accessibility is inherited entirely from
Link. - When
as="nav", the container has an accessible label vianavLabel→aria-label. - When
as="ul", valid<ul>/<li>semantics are maintained. - Invalid items remain visible —
Linkrenders them as non-interactive<span>elements. - A dev warning is emitted when
as="nav"is used withoutnavLabel.
Related
Section titled “Related”- Link — per-item rendering, styling, accessibility, and fallback behavior
- Button — shared variant system and visual language