Skip to content
WingoUI
ComponentsTemplatesDocsPricingAI agentsBlogChangelogContact
Components
Buttons & Actions
ButtonButton GroupCopy ButtonDelete ButtonTheme ToggleToggleToggle Group
Inputs
Avatar UploadCalendarCheckboxColor PickerComboboxCountry SelectCron PickerCurrency InputDate PickerDate Range PickerDate Time PickerDuration PickerEmail InputEmoji PickerFile UploadFilter BuilderInputInput GroupListboxMasked InputMention InputMonth PickerMulti SelectNumber InputOTP InputPassword InputPhone InputRadio GroupRatingSearch InputSegmented ControlSelectSignature PadSliderSwitchTag InputTextareaTime PickerTimezone SelectTree Select
Forms
Address InputBooking WidgetCSV ImportFieldForm WizardInline EditInvoice line itemsRich Text EditorSchema Builder
Navigation
Back To TopBounce SidebarBreadcrumbCommand MenuGlobal SearchGooey NavHook SidebarNav MenuNav TabsPaginationProximity SidebarScroll ProgressSidebarStepsTable Of ContentsTabsTopbarUser MenuWorkspace Switcher
Overlays
Alert DialogContext MenuDialogDrawerDropdown MenuFamily DrawerHover CardPopoverShare DialogSheetShortcuts DialogTooltipTour
Feedback
AlertBannerCookie ConsentEmoji ReactionEmpty StateNotification BellNotification CenterProgressRoute ProgressSetup ChecklistSkeletonSpinnerToast
Data Display
Approval FlowAvatarBadgeCalendar ViewCode BlockComment ThreadContact cardCountdownDescription ListDiff ViewerFile ListFile managerFolderGanttJSON ViewerKbdLog ViewerMarkdownPresenceSchedulerTagTimelineTree View
Tables & Lists
Audit LogData TableDeal PipelineEditable GridKanbanListMembers tablePermissions MatrixTableTask ListVirtual List
Charts & Stats
Animated CounterArea chartBar chartDonut chartFunnel chartGaugeGitHub ActivityHeatmap calendarLeaderboardLine chartRadar chartRadial barSparklineStat CardTrackerTrend badge
Layout
AccordionApp ShellCardCollapsibleDetail LayoutEntity HeaderPage HeaderScroll AreaSeparatorSettings LayoutSplit ViewToolbar
Media
Audio PlayerCarouselCSV ViewerDOCX EditorDOCX ViewerExcel ViewerFile SystemImage compareImage CropperImage GalleryImage LightboxLocation MapPDF ViewerPowerPoint ViewerQR CodeStep PlayerVideo Player
AI Kit
Agent Status CardChat MessageChat ThreadChat WidgetConversation ListFluid OrbGrid RevealMatrix OrbModel PickerPrompt InputReasoning IndicatorRule BuilderSuggestion ChipsTool Call TimelineUsage MeterVoice InputWorkflow Canvas
Text & Effects
Background PatternGravity LettersMarqueeTerminalText AnimateText Rotate
Mobile
Action SheetBottom Tab BarFABHaptic ButtonHero HeaderInstall PromptLarge Title HeaderNotification BannerOnboarding CarouselPicker WheelPull To RefreshSlide To ConfirmSticky CTA BarSwipe DeckSwipeable Tabs
Commerce
Cart drawerCategory pickerCheckout stepsCoupon inputFavorite buttonFilter panelListing cardListing gridOrder trackerPricePrice rangePricing tableProduct galleryQuantity stepperReviewsSeller card
Marketing Sections
App Download SectionBlog Cards SectionCTA SectionFAQ SectionFeature GridFeature ShowcaseHero SectionIntegrations SectionLogo CloudMarketing FooterMarketing HeaderMarketing SectionNewsletter SectionPricing SectionStats SectionSteps SectionTeam SectionTestimonials SectionTimeline SectionVideo Section
Blocks
Admin Dashboard PageAdmin ShellAI Chat PageAPI Keys PageAutomation Builder PageCheckout PageCRM Contact PageCRM Pipeline PageError PagesInbox PageInvoice PageKPI DashboardListing Detail PageLogin PageMarketplace Home PageMarketplace Search PageMarketplace ShellMobile App HomeOnboarding FlowOrder History PagePost Listing WizardPricing PageProfile PageRegister PageSettings PageUsers Admin Page
Templates
About PageAcademy PageAccessibility PageAffiliate PageAgency PageAI Product PageAppointment Booking PageBlog PageBlog Post PageBug Bounty PageCareers PageChangelog PageCommunity PageCompare PageContact PageCustomer Story PageCustomers PageDemo Booking PageDevelopers PageDocs Home PageDownload PageEnterprise PageEvents PageExperts PageFAQ PageFeature PageGlossary PageHelp Article PageHelp Center PageHome Services PageImpact PageIntegration Detail PageIntegrations PageJob Detail PageLanding PageLaunch PageLegal PageManifesto PagePortfolio PagePress PageProduct Tour PagePromo PageReal Estate PageReferral PageResearch Report PageRestaurant PageRoadmap PageROI Calculator PageSecurity PageSolutions PageStartups PageStatus PageStorefront PageSwitch PageTemplate Gallery PageTravel PageWaitlist PageYear in Review Page
Hooks & Utilities
AI ChatChart kitCommerceDate utilsFile exportFile typesFiltersForm validationHapticsInvoicingMotion presetsNavigationNumber formatRelative timeRomanian locationsSpreadsheetText matchTonesUIProvideruseClipboarduseConsentuseControllableStateuseCooldownuseDebounceuseKeyboardInsetuseLocaleuseLongPressuseMediaControlsuseMediaQueryuseOverflowItemsusePersistedStateuseScrollEdgesuseScrollStateuseSelectionuseShortcutuseStickToBottom
GalleryTheme

Data Display

Tag

Data Display

Tag React component for Tailwind CSS v4

SchedulerTimeline
Live props
Content
children
count
removeLabel
textValue
Appearance
variant
tone
color
size
radius
dot
selectedVariant
showCheck
Behavior
selectable
href
asChild
locale
State
defaultSelected
disabled
Code
import { Tag } from "@/components/ui/tag"

<Tag>New York</Tag>
  1. Home
  2. Components
  3. Data Display
  4. Tag
Pro

Tag React component for Tailwind CSS v4

v1.0.0·Added in 1.0.0

A React tag and chip component: toggling filter chips, removable tags, a dot, icon, avatar or count, in groups that wrap, scroll or fold.

Click a selectable tag to toggle it: it fills in and a check grows in on a quick spring while the chip widens smoothly. Click × to remove a tag; in a group the others slide into its place. With the keyboard a group is one Tab stop: Left / Right (and Up / Down) move between tags, Home / End jump to the ends, Space / Enter toggle, Backspace / Delete remove the focused tag and focus moves to the next one. A lone tag has its × in the Tab order and Backspace / Delete on it removes it too. In a collapsed group the +N tag opens a popover with the hidden tags; below 768px it is a bottom sheet listing them as rows you tap to toggle or remove. While it is open the rows stay put; newly selected tags move into the row when it closes, and Escape returns focus to +N. On a phone the scroll overflow is a swipeable filter bar that fades at its edges, and every chip and × gets a 44px hit area without growing.

Tag is a Pro React component in the React data display components category, written in TypeScript for React 19 and Tailwind CSS v4. It installs as source with npx wingo-ui@latest add tag, together with Avatar, Motion presets, Navigation, Number format, Popover and 8 more and the npm packages @radix-ui/react-slot, lucide-react and motion.

Add to a project

Requirements: React 19 and Tailwind CSS v4, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup

npx wingo-ui@latest add tag

Tag is part of Pro, with 298 more Pro items: $8 a month or $150 once. 14-day refund before you download any Pro item. See plans

Usage

Import Tag from @/components/ui/tag.

import { useState } from "react"
import { MapPin } from "lucide-react"
import { Tag, TagGroup, type TagItem } from "@/components/ui/tag"

const CITIES: TagItem[] = [
  { value: "new-york", label: "New York", count: 128 },
  { value: "chicago", label: "Chicago", count: 342 },
  { value: "seattle", label: "Seattle", count: 96 },
  { value: "austin", label: "Austin", count: 74 },
]

export function ListingFilters() {
  const [cities, setCities] = useState<string[]>(["new-york"])
  const [freeShipping, setFreeShipping] = useState(true)
  return (
    <div className="flex flex-col gap-3">
      <TagGroup
        label="Cities"
        items={CITIES}
        selectionMode="multiple"
        value={cities}
        onValueChange={setCities}
        overflow="scroll"
        locale="en-US"
      />
      {freeShipping && (
        <Tag icon={<MapPin />} onRemove={() => setFreeShipping(false)} removeLabel="Remove">
          Free shipping
        </Tag>
      )}
    </div>
  )
}

Props

  • childrendefault "New York"
    ReactNode

    The label. Long labels truncate at 16rem and show the full text in a title.

  • variantdefault "soft"
    "soft" | "outline" | "solid"

    soft is a tinted fill (a light gray for neutral), outline a hairline border, solid the full tone fill for the loudest labels.

  • tonedefault "neutral"
    "neutral" | "brand" | "success" | "warning" | "danger" | "info"

    Semantic color from the design tokens; it paints the fill, the text, the border and the dot.

  • colordefault ""
    string

    Any CSS color, for CRM or kanban labels. Replaces the tone; soft and outline mix it for contrast in both themes.

  • sizedefault "md"
    "sm" | "md" | "lg"

    24 / 28 / 32px tall, text 12 / 13 / 14px, icons 12 / 14 / 16px. On touch screens the chip keeps its look and gets a 44px hit area.

  • radiusdefault "full"
    "sm" | "md" | "full"

    6px, 8px or a pill.

  • dotdefault false
    boolean

    A leading 6px dot in the tone. An icon or an avatar takes its place when set.

  • selectedVariantdefault "solid"
    "solid" | "soft"

    The look while selected: a solid fill in the tone (black / white for neutral, like a pressed filter chip) or a toned soft fill with a border. Unselected filter chips stay neutral, so the tone marks only the selected ones.

  • showCheckdefault true
    boolean

    The check that scales in and draws itself while selected.

  • icon
    ReactNode

    A leading icon; unsized svgs follow the tag size.

  • avatar
    string | { src?: string; name: string }

    A leading avatar (16 / 20 / 24px). A string is a photo url; with a name the initials show while it loads.

  • countdefault ""
    number

    A trailing muted count ("Overdue 3"), formatted for the locale and read with the label. No count by default. In the demo an empty control shows 1,280 and any text that is not a number hides the count.

  • selectabledefault false
    boolean

    Makes the tag a toggle button (aria-pressed): a filter chip. For a row of chips with shared selection, use TagGroup (see Parts).

  • defaultSelecteddefault false
    boolean

    Starting state while uncontrolled.

  • selected
    boolean

    Controlled selected state; pair it with onSelectedChange.

  • onSelectedChange
    (selected: boolean) => void

    Fires when a selectable tag is toggled.

  • onRemove
    () => void

    Shows the × button. Backspace / Delete on the focused tag call it too.

  • removeLabeldefault "Remove"
    string

    The × button's aria-label, followed by the tag's text: "Remove New York". TagGroup takes a partial labels object instead (see DEFAULT_TAG_LABELS).

  • textValuedefault ""
    string

    The plain text of a label that is not a string, for the remove label and the title.

  • hrefdefault ""
    string

    Renders the tag as a link through the app's router link (NavLink from lib/navigation). The demo ignores it while asChild is on.

  • onClick
    (event: MouseEvent<HTMLElement>) => void

    Makes a plain pressable tag. On a selectable tag, preventDefault skips the toggle.

  • disableddefault false
    boolean

    Dims the tag and blocks pressing and removing it.

  • asChilddefault false
    boolean

    Renders your single child (an <a>, a router Link) as the pressable part, with the check, icon and count around its content. The demo swaps in a link.

  • localedefault ""
    string

    Intl locale for the count (1,280 in en-US, 1.280 in de-DE). Empty uses the UIProvider locale, then the page's. The demo passes en-US while it is empty.

  • classNames
    Partial<Record<"button" | "check" | "dot" | "icon" | "avatar" | "label" | "count" | "remove", string>>

    Extra classes for the inner parts.

  • className
    string

    Extra classes for the chip, merged last. Override the tone vars here, e.g. [--tone-foreground:white].

Parts

  • TagGroup

    component

    A row of tags from an items array with shared selection, removal and overflow. Roving focus: one Tab stop, arrow keys, Home / End, Space / Enter to toggle, Backspace / Delete to remove. In collapse mode the hidden tags open in a popover, or a bottom sheet below 768px. size, variant, tone, color, radius, selectedVariant, showCheck and disabled work as on Tag and apply to every item; an item's own tone and color win.

    • items*
      TagItem[]

      The tags to render (see TagItem).

    • selectionModedefault "none"
      "none" | "single" | "multiple"

      Whether tags toggle, and how many can be selected.

    • value
      string[]

      Controlled selected values; single mode keeps at most one.

    • defaultValuedefault "[]"
      string[]

      Selected values at first, uncontrolled.

    • onValueChange
      (value: string[]) => void

      Fires with the new selection.

    • onRemove
      (value: string) => void

      Shows × on every item whose removable is not false.

    • overflowdefault "wrap"
      "wrap" | "scroll" | "collapse"

      Wrap onto lines, one swipeable row with faded edges, or one row that folds extra tags into +N with selected ones pinned.

    • maxVisibledefault 0
      number

      Caps the visible tags before +N even when there is room; 0 means no cap.

    • label
      string

      The group's aria-label, e.g. "Cities".

    • labels
      Partial<TagLabels>

      Overrides for the +N text, its aria-label, the sheet title and the remove label.

    • container
      HTMLElement | null

      Portal target of the +N popover.

    • locale
      string

      Intl locale for the counts.

    • classNames
      Partial<Record<"tag" | "more" | "popover" | "row", string>>

      Extra classes for the inner parts.

  • DEFAULT_TAG_LABELS

    constant

    The English strings TagGroup uses: more (n => "+3"), moreLabel ("3 more: Boston, Denver, Seattle"), moreTitle ("More") and remove ("Remove"). Spread it to translate a few.

  • TagItem

    type

    One tag of a TagGroup: { value, label, textValue?, icon?, avatar?, dot?, tone?, color?, count?, disabled?, removable?, href? }.

  • TagLabels

    type

    The shape of the labels object: more, moreLabel, moreTitle and remove.

Examples

Applied filters

Removable tags with a clear-all action; the others slide into place. Backspace removes the focused one.

CRM labels

Dots in status tones and custom colors, with a count read together with the label.

People chips

Avatars at the start, removable like assignees, plus a pressable add tag.

Collapse into +N

One row in a narrow card; the rest fold into +N, a popover on desktop and a sheet on phones.

Phone filter bar

overflow="scroll": one swipeable row with snap and faded edges, single selection.

Single choice in a tone

selectionMode="single" with the soft selected look in brand orange.

Sizes, variants and selected looks

24 / 28 / 32px, soft / outline / solid, the two selected looks, radii and disabled.

Dependencies

@radix-ui/react-slotlucide-reactmotionavatarmotionnavigationnumber-formatpopovertonesui-configuse-controllable-stateuse-localeuse-media-queryuse-overflow-itemsuse-scroll-edgesuse-selection

Files

  • components/ui/tag.tsx

FAQ

Is the React Tag component free?

The preview, props and docs are free; copying the source needs a Pro plan. See plans.

How do I install Tag?

Run npx wingo-ui@latest add tag. It also adds the Wingo UI items it builds on (Avatar, Motion presets, Navigation, Number format, Popover and 8 more) and the npm packages @radix-ui/react-slot, lucide-react and motion. With shadcn, add the @wingo-ui registry with your API key, then run npx shadcn@latest add @wingo-ui/tag.

How does Tag behave on phones?

In a collapsed group the +N tag opens a popover with the hidden tags; below 768px it is a bottom sheet listing them as rows you tap to toggle or remove. On a phone the scroll overflow is a swipeable filter bar that fades at its edges, and every chip and × gets a 44px hit area without growing.

See also

BadgeTag InputToggle GroupToolbarAvatar

Used in

Onboarding FlowMarketplace Home PageKanbanReviewsCoupon inputFilter panelTree SelectContact cardLog ViewerPrice rangeAutomation Builder PageCRM Contact Page

and 6 more.

More React data display components

TimelineTree ViewKbdFile managerCountdownApproval Flow
All 23 React data display components
PreviousSchedulerNext Timeline
Northwind Realty

Filter listings

224 listings
New York, 1,280

The controls drive this tag; × or Backspace removes it.