Lunia DS

Base components

Badge group

A pill link that holds a small badge and a short message, for announcements at the top of a page, which eases its colors on hover and nudges its arrow toward the link target.

Loading preview

Four badge groups above a page heading: leading "New" with "Projects now support shared views" (Pill color, Brand), trailing "Read the update" with "Version 2.4 is available" (Badge modern, Gray), and Error and Success versions at size lg. Replay hovers the first one.

Installation

Run this in your app after the one-time setup on the Getting started page.

$ npx @ganisigit/lunia-ds add badge-group

Usage

The demo above, as code.

demo.tsx
'use client';

import * as React from 'react';
import { BadgeGroup } from './badge-group';

export default function BadgeGroupDemo({ replay = 0 }: { replay?: number }) {
  const [hovered, setHovered] = React.useState(false);

  // Replay shows the hover look of the first badge group for a moment.
  React.useEffect(() => {
    if (replay === 0) return;
    setHovered(true);
    const timer = window.setTimeout(() => setHovered(false), 900);
    return () => window.clearTimeout(timer);
  }, [replay]);

  return (
    <div className="flex flex-col items-center gap-4">
      <BadgeGroup badge="New" color="brand" data-hovered={hovered ? '' : undefined}>
        Projects now support shared views
      </BadgeGroup>
      <BadgeGroup badge="Read the update" badgePosition="trailing" type="badge-modern" color="gray">
        Version 2.4 is available
      </BadgeGroup>
      <BadgeGroup badge="Error" color="error" size="lg">
        Payments are paused for this account
      </BadgeGroup>
      <BadgeGroup badge="Done" type="badge-modern" color="success" size="lg">
        Your workspace is ready
      </BadgeGroup>
    </div>
  );
}

API

Parts: root (link or button, pill or rounded box), badge (small inner badge with its own fill and border), message (text, or a dot and text for Badge modern), arrow icon (after the message, or inside the trailing badge).

PropTypeDefaultDescription
badgestringundefinedText of the inner badge, for example "New".
badgePosition"leading" | "trailing""leading"Side of the message where the inner badge sits. With trailing, the arrow moves into the badge.
type"pill-color" | "badge-modern""pill-color"pill-color: a round pill in the color set. badge-modern: a neutral rounded box with a colored dot and a small shadow.
color"brand" | "gray" | "error" | "warning" | "success""brand"Color set from the utility color tokens, as in Badge.
size"md" | "lg""md"30 or 32px tall; Text xs or Text sm.
iconbooleantrueShows the arrow icon.
hrefstringundefinedRenders a link. Without href the root is a button and fires click.
disabledbooleanfalseTurns the button off (50% opacity). Links are not disabled; hide them instead.
EventDescription
clickFires on activation when there is no href.
SlotDescription
defaultMessage text.
iconReplaces the arrow icon.

Motion

Every row names a token from the Motion page. The last column says what happens when the user asks for reduced motion.

IDTriggerElementPropertyFrom → toTimingReduced motion
BGP1hoverroot, inner badgebackground-color, border-colorDefault colors (for example utility-brand-50) → Hover colors (for example utility-brand-100)duration-sm (200)ease-outSwaps at once
BGP2hoverarrow icontranslate-x0 → distance-rise (toward the link target)duration-sm (200)ease-outStays still
BGP3hover endsarrow icontranslate-xdistance-rise → 0duration-xs (160)ease-exitStays still
BGP4pressrootscale1 → scale-pressduration-sm (200)ease-outStays still
BGP5keyboard focusrootbox-shadownone → focus ring (2px bg-primary gap, 4px focus-ring)duration-2xs (120)ease-outShows at once

Accessibility

  • With href the root is a native link; without it, a native button. The whole pill is one target and one tab stop.
  • The accessible name is the badge text and the message in reading order (for example "New Projects now support shared views"); the arrow and the dot are aria-hidden.
  • When color carries meaning (Error, Warning), the badge text says it in words.
  • Size md is 30px tall, so the target meets the 24px minimum (WCAG 2.5.8).
  • Reduced motion: colors swap at once, the arrow does not move and the pill does not scale.