Component

Tag

Build filter tags with pressed state, optional counts, prefix and suffix slots, and a dismiss action.

Interactive preview

Usage

Import the component entry and start with its smallest complete example.

Import

import { Tag } from "@chitrank2050/monoline-ui/tag"

Basic usage

// 1. Unselected filter with prefix (dashed border)
<Tag prefix="Environment">Production</Tag>

// 2. Selected filter with dismiss ✕ button
<Tag prefix="Status" selected onDismiss={() => handleClear("Status")}>
  Error
</Tag>

// 3. Selected category with suffix count
<Tag selected suffix="3">
  Professional
</Tag>

// 4. Plain counter tag
<Tag>6 errors</Tag>

Usage guidance

Choose the component for its interaction model and semantics before customizing its appearance.

01
Use when

Use Tag for one filter or a compact, non-interactive category label.

02
Avoid when

The tag navigates, belongs to a mutually exclusive group, or changes a persistent setting.

03
Accessibility

An interactive Tag is a button with aria-pressed; a static Tag is a span. Any element supplied through asChild must preserve equivalent semantics.

04
Server Component

This component can render without adding a Monoline client boundary when its children and props are serializable.

API reference

Props, slots, and callbacks available on this component.

prefixReactNodeMuted key label with subtle opacity (e.g. 'Status', 'Author', 'Environment')
suffixReactNodeMuted suffix or count badge with subtle opacity (e.g. '3', 'items')
selectedbooleanSolid border with elevated surface fill and highlighted text. Renders circular ✕ if onDismiss is provided
onDismiss() => voidCallback when the ✕ dismiss button is clicked
dismissAriaLabelstringAccessible label for the dismiss button (defaults to 'Remove filter')
size"sm" | "md" | "lg"Maintains exact foundation height, padding, and font-size tokens
activebooleanAlias for selected
childrenReactNodeMain tag value or descriptive label

Design tokens

Theme variables this component reads for color, spacing, and motion.

--duration-microCSS varTransition duration for hover and active state transitions
--border-strongCSS varBorder color for dashed unselected and solid active states
--buttonCSS varSubtle elevated surface fill for active and hovered tags
--button-hoverCSS varElevated surface fill for hover on active tags and dismiss button
--text-mutedCSS varPrefix, suffix, and unselected default text color
--textCSS varHover and active value text color

Implementation

The source used by the example above, including any state it needs.

import { useState } from "react"
import { Tag } from "@chitrank2050/monoline-ui/tag"

export function FilterToolbar() {
  const [selectedStatus, setSelectedStatus] = useState<string | null>("Error")
  const [selectedAuthor, setSelectedAuthor] = useState<string | null>("chitrank2050")
  const [selectedCategory, setSelectedCategory] = useState<string | null>("Professional")

  return (
    <div className="flex flex-wrap items-center gap-2">
      <Tag
        prefix="Status"
        selected={selectedStatus !== null}
        onClick={() => setSelectedStatus(selectedStatus ? null : "Error")}
        onDismiss={() => setSelectedStatus(null)}
      >
        {selectedStatus ?? "All"}
      </Tag>

      <Tag
        prefix="Author"
        selected={selectedAuthor !== null}
        onClick={() => setSelectedAuthor(selectedAuthor ? null : "chitrank2050")}
        onDismiss={() => setSelectedAuthor(null)}
      >
        {selectedAuthor ?? "All"}
      </Tag>

      <Tag
        suffix="3"
        selected={selectedCategory === "Professional"}
        onClick={() =>
          setSelectedCategory(
            selectedCategory === "Professional" ? null : "Professional"
          )
        }
      >
        Professional
      </Tag>

      <Tag prefix="Environment">Production</Tag>
    </div>
  )
}