Base Components
Tag
Efficient tool for categorizing and labeling content within your application.
Tag
Installation
Install the following dependencies:
npm install @radix-ui/react-slotCreate a tag.tsx file and paste the following code into it.
// CoreUI Tag v0.0.0import * as React from 'react';import { Slot } from '@radix-ui/react-slot';import { RiCloseFill } from '@remixicon/react';import { PolymorphicComponentProps } from '@/utils/polymorphic';import { recursiveCloneChildren } from '@/utils/recursive-clone-children';import { tv, type VariantProps } from '@/utils/tv';const TAG_ROOT_NAME = 'TagRoot';const TAG_ICON_NAME = 'TagIcon';const TAG_DISMISS_BUTTON_NAME = 'TagDismissButton';const TAG_DISMISS_ICON_NAME = 'TagDismissIcon';export const tagVariants = tv({ slots: { root: [ 'group/tag inline-flex h-6 items-center gap-2 rounded-md px-2 text-label-xs text-text-sub-600', 'transition duration-200 ease-out', 'ring-1 ring-inset', ], icon: [ // base '-mx-1 size-4 shrink-0 text-text-soft-400 transition duration-200 ease-out', // hover 'group-hover/tag:text-text-sub-600', ], dismissButton: [ // base 'group/dismiss-button -ml-1.5 -mr-1 size-4 shrink-0', // focus 'focus:outline-none', ], dismissIcon: 'size-4 text-text-soft-400 transition duration-200 ease-out', }, variants: { variant: { stroke: { root: [ // base 'bg-bg-white-0 ring-stroke-soft-200', // hover 'hover:bg-bg-weak-50 hover:ring-transparent', // focus-within 'focus-within:bg-bg-weak-50 focus-within:ring-transparent', ], dismissIcon: [ // hover 'group-hover/dismiss-button:text-text-sub-600', // focus 'group-focus/dismiss-button:text-text-sub-600', ], }, gray: { root: [ // base 'bg-bg-weak-50 ring-transparent', // hover 'hover:bg-bg-white-0 hover:ring-stroke-soft-200', ], }, }, disabled: { true: { root: 'pointer-events-none bg-bg-weak-50 text-text-disabled-300 ring-transparent', icon: 'text-text-disabled-300 [&:not(.remixicon)]:opacity-[.48]', dismissIcon: 'text-text-disabled-300', }, }, }, defaultVariants: { variant: 'stroke', },});type TagSharedProps = VariantProps<typeof tagVariants>;type TagProps = VariantProps<typeof tagVariants> & React.HTMLAttributes<HTMLDivElement> & { asChild?: boolean; };const TagRoot = React.forwardRef<HTMLDivElement, TagProps>( ( { asChild, children, variant, disabled, className, ...rest }, forwardedRef, ) => { const uniqueId = React.useId(); const Component = asChild ? Slot : 'div'; const { root } = tagVariants({ variant, disabled }); const sharedProps: TagSharedProps = { variant, disabled, }; const extendedChildren = recursiveCloneChildren( children as React.ReactElement[], sharedProps, [TAG_ICON_NAME, TAG_DISMISS_BUTTON_NAME, TAG_DISMISS_ICON_NAME], uniqueId, asChild, ); return ( <Component ref={forwardedRef} className={root({ class: className })} aria-disabled={disabled} {...rest} > {extendedChildren} </Component> ); },);TagRoot.displayName = TAG_ROOT_NAME;function TagIcon<T extends React.ElementType>({ className, variant, disabled, as, ...rest}: PolymorphicComponentProps<T, TagSharedProps>) { const Component = as || 'div'; const { icon } = tagVariants({ variant, disabled }); return <Component className={icon({ class: className })} {...rest} />;}TagIcon.displayName = TAG_ICON_NAME;type TagDismissButtonProps = TagSharedProps & React.ButtonHTMLAttributes<HTMLButtonElement> & { asChild?: boolean; };const TagDismissButton = React.forwardRef< HTMLButtonElement, TagDismissButtonProps>( ( { asChild, children, className, variant, disabled, ...rest }, forwardedRef, ) => { const Component = asChild ? Slot : 'button'; const { dismissButton } = tagVariants({ variant, disabled }); return ( <Component ref={forwardedRef} className={dismissButton({ class: className })} {...rest} > {children ?? ( <TagDismissIcon variant={variant} disabled={disabled} as={RiCloseFill} /> )} </Component> ); },);TagDismissButton.displayName = TAG_DISMISS_BUTTON_NAME;function TagDismissIcon<T extends React.ElementType>({ className, variant, disabled, as, ...rest}: PolymorphicComponentProps<T, TagSharedProps>) { const Component = as || 'div'; const { dismissIcon } = tagVariants({ variant, disabled }); return <Component className={dismissIcon({ class: className })} {...rest} />;}TagDismissIcon.displayName = TAG_DISMISS_ICON_NAME;export { TagRoot as Root, TagIcon as Icon, TagDismissButton as DismissButton, TagDismissIcon as DismissIcon,};Examples
Stroke (Default)
Tag
Customer
Gray
Tag
Customer
Disabled
Tag
Customer
Tag
Customer
With Image
With Avatar
Dismissable
Tag
Customer
Tag
Customer
API Reference
Tag.Root
This component is based on the <div> element and supports all of its props. And adds:
| Prop | Type | Default |
|---|---|---|
variant | "stroke" | "gray" | "stroke" |
disabled | boolean | |
asChild | boolean |
Tag.Icon
The Tag.Icon component is polymorphic, allowing you to change the underlying HTML element using the as prop.
| Prop | Type | Default |
|---|---|---|
as | React.ElementType | div |
Tag.DismissButton
This component is based on the <button> element and supports all of its props. And adds:
| Prop | Type | Default |
|---|---|---|
asChild | boolean |
Tag.DismissIcon
The Tag.DismissIcon component is polymorphic, allowing you to change the underlying HTML element using the as prop.
| Prop | Type | Default |
|---|---|---|
as | React.ElementType | div |