npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@xsolla/xui-tag

v0.209.1

Published

A cross-platform React tag component for displaying labels, categories, and removable chips. Supports multiple tones, solid/outlined types, and optional left/right icons. <!-- BEGIN:xui-mcp-instructions:tag --> A compact label chip used to categorise, cla

Readme

Tag

A cross-platform React tag component for displaying labels, categories, and removable chips. Supports multiple tones, solid/outlined types, and optional left/right icons.

A compact label chip used to categorise, classify, or annotate content. Renders as a pill-shaped container with a text label and optional leading and trailing icons. Supports two visual types (solid fill and outlined), seven semantic tones, and five sizes. Used in lists, cards, table cells, filters, and any context where a short categorical attribute needs to be visually marked.

When to use

  • To display a category, status, or attribute as a persistent visual marker — e.g. "New", "Beta", "Sale", "Featured"
  • To represent a selected filter or active facet in a filter bar
  • To show a label on a card, list item, or table row when a colour-coded semantic signal is needed
  • In multi-tag groups where several attributes must be shown simultaneously on one item

When not to use

  • For interactive toggleable filters — use ToggleButtonGroup or a checkable chip pattern
  • For operational statuses with complex state logic — use StatusDropdown or Badge
  • For dismissible user-entered tags — add a remove (✕) button in the Icon right slot
  • When the label is purely decorative with no semantic meaning — use a styled text span instead

Content guidelines

  • Label text — keep tag labels short: 1–3 words maximum. Use title case for category labels ("New", "On Sale", "Beta") and sentence case for descriptive labels ("Out of stock").
  • Avoid redundancy — if an icon already communicates the meaning (e.g. a checkmark for verified), the label "Verified" may be redundant in very compact contexts. In most cases, keep both for clarity.
  • Consistent vocabulary — use the same label text for the same semantic state across the entire product. Do not use "Beta" in one place and "Preview" in another for the same concept.
  • No punctuation — do not end tag labels with periods, commas, or colons.

Behaviour guidelines

  • Read-only vs interactive — by default, Tag is a display component with no built-in interactive states. If a tag must be dismissible, add a trailing remove icon (Icon right=true with an ✕ icon) and handle the click at the product level. If a tag must be selectable/toggleable, consider ToggleButtonGroup instead.
  • Removable tags — when using Icon right as a remove button, the click target for removal should be the icon alone, not the entire tag. Give the remove icon an aria-label="Remove [tag label]" and handle the action separately from any click on the tag's label area.
  • Tag groups — when multiple tags appear together (e.g. on a product card), render them in a wrapping flex row with consistent gap. Define a maximum number of visible tags and show a "+N more" indicator when exceeded.
  • Overflow — tag labels must not wrap to multiple lines. If the label is too long to fit on one line within the chosen size, truncate with ellipsis and show the full text in a tooltip.
  • Colour consistency — use the same Tone for the same semantic category across all surfaces in the product. Establish a tone-to-category mapping in the product's design token system and apply it uniformly.
  • Type selection — use Type=Solid as the default. Switch to Type=Outlined when the tag is placed on a coloured surface (e.g. inside a coloured card or over a photo) where a solid fill would be visually too heavy.

Accessibility

  • If the tag is a purely decorative label with no actionable meaning, it can have role="presentation" and aria-hidden="true" when the surrounding context already communicates its meaning.
  • If the tag communicates meaningful state information (e.g. "New", "Sale", "Out of stock"), it must be readable by screen readers. Ensure it is not hidden from the accessibility tree.
  • Do not rely on Tone (colour) alone to communicate meaning — the label text or icon must also be present (WCAG 1.4.1 Use of Colour). For icon-only tags, provide aria-label on the element.
  • Removable tags: the remove button (Icon right) must have aria-label="Remove [tag name]" so screen readers can announce which tag is being removed. The button must be focusable and respond to Enter / Space.
  • When tags are inside a list, wrap them in a with elements and an aria-label on the list describing the group — e.g. aria-label="Product tags".
  • Ensure sufficient colour contrast between the tag label text and the tag background in both Solid and Outlined variants, for all tones, meeting WCAG AA (4.5:1 for small text at XS/S sizes).

Installation

npm install @xsolla/xui-tag

Demo

Basic Tag

import * as React from "react";
import { Tag } from "@xsolla/xui-tag";

export default function BasicTag() {
  return (
    <div style={{ display: "flex", gap: 8 }}>
      <Tag>Default</Tag>
      <Tag tone="brand">Brand</Tag>
      <Tag tone="success">Success</Tag>
    </div>
  );
}

Tag Tones

import * as React from "react";
import { Tag } from "@xsolla/xui-tag";

export default function TagTones() {
  return (
    <div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
      <Tag tone="primary">Primary</Tag>
      <Tag tone="brand">Brand</Tag>
      <Tag tone="brandExtra">Brand Extra</Tag>
      <Tag tone="success">Success</Tag>
      <Tag tone="warning">Warning</Tag>
      <Tag tone="alert">Alert</Tag>
      <Tag tone="neutral">Neutral</Tag>
    </div>
  );
}

Tag Sizes

import * as React from "react";
import { Tag } from "@xsolla/xui-tag";

export default function TagSizes() {
  return (
    <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
      <Tag size="xs">Extra Small</Tag>
      <Tag size="sm">Small</Tag>
      <Tag size="md">Medium</Tag>
      <Tag size="lg">Large</Tag>
      <Tag size="xl">Extra Large</Tag>
    </div>
  );
}

Solid vs Outlined

import * as React from "react";
import { Tag } from "@xsolla/xui-tag";

export default function TagTypes() {
  return (
    <div style={{ display: "flex", gap: 8 }}>
      <Tag tone="brand" type="solid">
        Solid
      </Tag>
      <Tag tone="brand" type="outlined">
        Outlined
      </Tag>
    </div>
  );
}

Tag with Icons

import * as React from "react";
import { Tag } from "@xsolla/xui-tag";
import { Check } from "@xsolla/xui-icons";
import { Star, Clock } from "@xsolla/xui-icons-base";

export default function TagWithIcon() {
  return (
    <div style={{ display: "flex", gap: 8 }}>
      <Tag iconLeft={<Star size={12} />} tone="warning">
        Featured
      </Tag>
      <Tag iconLeft={<Check size={12} />} tone="success">
        Verified
      </Tag>
      <Tag
        iconLeft={<Clock size={12} />}
        iconRight={<Star size={12} />}
        tone="neutral"
      >
        Pending
      </Tag>
    </div>
  );
}

Icon-Only Tag

import * as React from "react";
import { Tag } from "@xsolla/xui-tag";
import { Check } from "@xsolla/xui-icons";

export default function IconOnlyTag() {
  return <Tag iconLeft={<Check size={12} />} tone="success" />;
}

Removable Tag

import * as React from "react";
import { Tag } from "@xsolla/xui-tag";

export default function RemovableTag() {
  const [tags, setTags] = React.useState([
    "React",
    "TypeScript",
    "Node.js",
    "GraphQL",
  ]);

  const removeTag = (tagToRemove: string) => {
    setTags(tags.filter((tag) => tag !== tagToRemove));
  };

  return (
    <div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
      {tags.map((tag) => (
        <Tag key={tag} tone="brand" onRemove={() => removeTag(tag)}>
          {tag}
        </Tag>
      ))}
    </div>
  );
}

Anatomy

Import the component and use it directly:

import { Tag } from "@xsolla/xui-tag";

<Tag
  size="md" // Size variant
  tone="brand" // Color tone
  type="solid" // Solid or outlined
  iconLeft={<Icon />} // Optional leading icon
  iconRight={<Icon />} // Optional trailing icon
  onRemove={handleRemove} // Makes tag removable (renders X icon)
>
  Tag Label
</Tag>;

Examples

Category Tags

import * as React from "react";
import { Tag } from "@xsolla/xui-tag";

export default function CategoryTags() {
  const categories = [
    { name: "Technology", tone: "brand" as const },
    { name: "Design", tone: "brandExtra" as const },
    { name: "Marketing", tone: "success" as const },
    { name: "Sales", tone: "warning" as const },
  ];

  return (
    <div style={{ display: "flex", gap: 8 }}>
      {categories.map((cat) => (
        <Tag key={cat.name} tone={cat.tone} size="sm">
          {cat.name}
        </Tag>
      ))}
    </div>
  );
}

Status Tags

import * as React from "react";
import { Tag } from "@xsolla/xui-tag";
import { CheckCircle, Clock, XCircle } from "@xsolla/xui-icons-base";

export default function StatusTags() {
  return (
    <div style={{ display: "flex", gap: 8 }}>
      <Tag iconLeft={<CheckCircle size={12} />} tone="success">
        Completed
      </Tag>
      <Tag iconLeft={<Clock size={12} />} tone="warning">
        In Progress
      </Tag>
      <Tag iconLeft={<XCircle size={12} />} tone="alert">
        Failed
      </Tag>
    </div>
  );
}

Tag Input

import * as React from "react";
import { Tag } from "@xsolla/xui-tag";
import { Input } from "@xsolla/xui-input";

export default function TagInput() {
  const [tags, setTags] = React.useState(["react", "typescript"]);
  const [inputValue, setInputValue] = React.useState("");

  const addTag = () => {
    if (inputValue.trim() && !tags.includes(inputValue.trim())) {
      setTags([...tags, inputValue.trim()]);
      setInputValue("");
    }
  };

  return (
    <div>
      <div
        style={{ display: "flex", gap: 8, flexWrap: "wrap", marginBottom: 8 }}
      >
        {tags.map((tag) => (
          <Tag
            key={tag}
            tone="primary"
            onRemove={() => setTags(tags.filter((t) => t !== tag))}
          >
            {tag}
          </Tag>
        ))}
      </div>
      <Input
        value={inputValue}
        onChangeText={setInputValue}
        placeholder="Add a tag..."
        onKeyDown={(e) => e.key === "Enter" && addTag()}
      />
    </div>
  );
}

API Reference

Tag

A tag/chip component.

Tag Props:

| Prop | Type | Default | Description | | :-------- | :--------------------------------------------------------------------------------------- | :---------- | :------------------------------------------------------------------------------------------------------------ | | testID | string | — | Test ID for testing frameworks. On web this renders as data-testid; on React Native it renders as testID. | | children | ReactNode | - | Tag content. Optional for icon-only tags. | | size | "xl" \| "lg" \| "md" \| "sm" \| "xs" | "md" | Size of the tag. | | tone | "primary" \| "brand" \| "brandExtra" \| "success" \| "warning" \| "alert" \| "neutral" | "primary" | Color tone. | | type | "solid" \| "outlined" | "solid" | Visual type. Solid fills background; outlined uses a border with lighter background. | | iconLeft | ReactNode | - | Leading icon. | | iconRight | ReactNode | - | Trailing icon. | | onRemove | () => void | - | Callback for remove button. Renders an X icon in the trailing position. |

Solid Tone Color Mapping:

| Tone | Background | Text | | :--------- | :----------------- | :-------------- | | primary | Background primary | Content primary | | brand | Brand primary | On brand | | brandExtra | BrandExtra primary | On brandExtra | | success | Success primary | On success | | warning | Warning primary | On warning | | alert | Alert primary | On alert | | neutral | Neutral primary | On neutral |

Outlined Tone Color Mapping:

| Tone | Background | Border | Text | | :--------- | :------------------- | :---------------- | :------------------------- | | primary | Background primary | Border secondary | Content primary | | brand | Brand secondary | Border brand | Content brand primary | | brandExtra | BrandExtra secondary | Border brandExtra | Content brandExtra primary | | success | Success secondary | Border success | Content success primary | | warning | Warning secondary | Border warning | Content warning primary | | alert | Alert secondary | Border alert | Content alert primary | | neutral | Neutral secondary | Border neutral | Content neutral primary |

Accessibility

  • Uses semantic elements for proper structure
  • Remove button includes accessible label
  • Keyboard accessible remove action
  • Focus indicator on interactive elements