Badge
badgeuiSmall inline label for status, counts, or tags — sits beside other content, not as a standalone control. Seven variants: `default`, `secondary`, `destructive`, `outline`, `success`, `warning`, `info`.
Installation
$pnpm dlx shadcn@latest add https://uipkge.dev/r/lit/badge.json$npx shadcn@latest add https://uipkge.dev/r/lit/badge.json$yarn dlx shadcn@latest add https://uipkge.dev/r/lit/badge.json$bunx shadcn@latest add https://uipkge.dev/r/lit/badge.jsonManifest:
https://uipkge.dev/r/lit/badge.jsonInstalls to:src/uip/components/badge/Examples
Loading interactive previews…
Loading interactive previews…
Props
| Name | Type / Values | Default | Required |
|---|---|---|---|
variant | 'default''secondary''destructive''outline''success''warning''info' | default | optional |
wrap | boolean | false | optional |
href | string | — | optional |
target | string | — | optional |
Schema
Type aliases from this item's source — use them to shape the data you pass in.
HTMLElementTagNameMapinterface HTMLElementTagNameMap {
'uip-badge': UipBadge
}
}npm dependencies
Includes
Used by
announcement-bannerbento-01careers-job-boardcart-drawerchangelogcoming-sooncontact-01cookie-consent-barcta-01cta-final-bandcustomer-reviewsdata-table-pageenterprise-workspace-switcherevent-listfaq-01faq-two-columnfeature-alternating-rowsfeature-interactive-tabsfeatures-01flash-sale-offer-barfooterfrequently-bought-togetherheaderherohero-01kanban-task-boardleaflet-maplogin-01logo-cloud-grayscalelogosnewsletternotification-centernotifications-popoveronboarding-wizardorder-confirmationorder-management-pagepricingpricing-01pricing-matrix-plan-cardsproduct-detail-pageproduct-grid-pageproduct-qa-communityproject-roadmaprecord-detail-pagesearch-results-pagestats-bandteam-sectiontechnical-specs-sheettestimonialtestimonial-marquee-scrolluser-profile-page
Files installed (2)
src/uip/components/badge/badge.ts2.3 kB
import { LitElement, css, html, nothing } from 'lit' import { cn } from '../../lib/utils' import { tailwind } from '../../lib/styles' import { ThemeController } from '../../lib/theme' import { badgeVariants, type BadgeVariants } from './badge.variants' type Variant = NonNullable<BadgeVariants['variant']> /** * <uip-badge> — the registry Badge as a web component. * * Class strings are React's `badgeVariants` verbatim. Shadow-DOM adaptations: * - `[&>svg]:…` / `[&>span]:min-w-0` can't see slotted children, so they are * repeated as `::slotted(svg)` / `::slotted(span)` on the <slot>; * - `href` renders an <a> (the stand-in for React's `asChild` + <a>), which * is what makes the `[a&]:hover:*` variants apply. * Class overrides (React's `className`) target the inner element through * `::part(base)`, e.g. `class="[&::part(base)]:px-3"`. */ export class UipBadge extends LitElement { // :host display can't be a utility class (the host has no template of its own). static styles = [tailwind, css`:host { display: inline-flex; }`] static properties = { variant: { reflect: true }, wrap: { type: Boolean, reflect: true }, href: {}, target: {}, } variant: Variant = 'default' wrap = false href?: string target?: string constructor() { super() new ThemeController(this) } connectedCallback() { super.connectedCallback() this.setAttribute('data-uipkge', '') this.setAttribute('data-slot', 'badge') } render() { // cn() like React's cn(badgeVariants(…), className): twMerge resolves `wrap`'s // whitespace-normal / rounded-lg / py-1 against the base classes. const classes = cn(badgeVariants({ variant: this.variant, wrap: this.wrap || undefined })) const slot = html`<slot class="[&::slotted(svg)]:size-3 [&::slotted(svg)]:shrink-0 [&::slotted(svg)]:pointer-events-none [&::slotted(span)]:min-w-0" ></slot>` if (this.href) { return html`<a part="base" data-slot="badge" class=${classes} href=${this.href} target=${this.target ?? nothing} >${slot}</a >` } return html`<span part="base" data-slot="badge" class=${classes}>${slot}</span>` } } customElements.get('uip-badge') || customElements.define('uip-badge', UipBadge) declare global { interface HTMLElementTagNameMap { 'uip-badge': UipBadge } }src/uip/components/badge/badge.variants.ts2.3 kB
import type { VariantProps } from 'class-variance-authority' import { cva } from 'class-variance-authority' /** * Variant definitions live in their own file (rather than the package * `index.ts`) so consuming Vue SFCs can import without creating a circular * dependency through the index. See card.variants.ts for the canonical * example + the SSR symptom that motivated the split. */ export const badgeVariants = cva( // text-overflow/ellipsis cannot apply to a flex container's anonymous text, // so truncation is opt-in via a child span (`<Badge><span class="truncate"> // …</span></Badge>`); min-w-0 lets that span shrink inside the flex root. 'inline-flex items-center justify-center rounded-full border px-2 py-0.5 text-xs font-medium w-fit max-w-full whitespace-nowrap shrink-0 [&>svg]:size-3 [&>svg]:shrink-0 [&>span]:min-w-0 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-colors duration-200 overflow-hidden', { variants: { variant: { default: 'border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90', secondary: 'border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90', destructive: 'border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60', outline: 'text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground', success: 'border-transparent bg-success/10 text-success dark:text-success [a&]:hover:bg-success/20', warning: 'border-transparent bg-warning/10 text-warning dark:text-warning [a&]:hover:bg-warning/20', info: 'border-transparent bg-info/10 text-info dark:text-info [a&]:hover:bg-info/20', }, // Allow multi-line labels. rounded-lg + extra leading keeps a wrapped // badge readable instead of a cramped two-line stadium pill. wrap: { true: 'whitespace-normal rounded-lg py-1 leading-snug', }, }, defaultVariants: { variant: 'default', }, }, ) export type BadgeVariants = VariantProps<typeof badgeVariants>
Raw manifest:https://uipkge.dev/r/lit/badge.json