Badge
Displays a badge or a component that looks like a badge.
BadgeSecondaryDestructiveOutline
Verified89920+
import { css } from 'remix/component'
import { Badge } from '#app/ui/badge.tsx'
import { BadgeCheckIcon } from '#app/ui/icons.tsx'
const row = css({ display: 'flex', width: '100%', flexWrap: 'wrap', gap: '0.5rem' })import { css } from 'remix/component'
import { Badge } from '#app/ui/badge.tsx'
import { BadgeCheckIcon } from '#app/ui/icons.tsx'
const row = css({ display: 'flex', width: '100%', flexWrap: 'wrap', gap: '0.5rem' })
const counter = css({
height: '1.25rem',
minWidth: '1.25rem',
borderRadius: '9999px',
paddingInline: '0.25rem',
fontFamily: 'var(--font-mono)',
fontVariantNumeric: 'tabular-nums',
})
export function BadgeDemo() {
return () => (
<div mix={css({ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '0.5rem' })}>
<div mix={row}>
<Badge>Badge</Badge>
<Badge variant="secondary">Secondary</Badge>
<Badge variant="destructive">Destructive</Badge>
<Badge variant="outline">Outline</Badge>
</div>
<div mix={row}>
<Badge
variant="secondary"
mix={css({
backgroundColor: 'oklch(62.3% 0.214 259.815)',
color: 'white',
'.dark &': { backgroundColor: 'oklch(54.6% 0.245 262.881)' },
})}
>
<BadgeCheckIcon />
Verified
</Badge>
<Badge mix={counter}>8</Badge>
<Badge mix={counter} variant="destructive">
99
</Badge>
<Badge mix={counter} variant="outline">
20+
</Badge>
</div>
</div>
)
}Installation
$ bunx --bun shadcn@latest add https://www.shadcn-remix.com/r/badge.json$ npx shadcn@latest add https://www.shadcn-remix.com/r/badge.json$ pnpm dlx shadcn@latest add https://www.shadcn-remix.com/r/badge.json$ yarn dlx shadcn@latest add https://www.shadcn-remix.com/r/badge.jsonInstall the following dependencies:
$ bun add remix$ npm install remix$ pnpm add remix$ yarn add remixCopy and paste the following code into your project.
import { css, type CSSMixinDescriptor, type Handle, type Props } from 'remix/component'
export type BadgeVariant = 'default' | 'secondary' | 'destructive' | 'outline' | 'ghost' | 'link'
export interface BadgeVariantOptions {
variant?: BadgeVariant
}
export interface BadgeProps extends Props<'span'>, BadgeVariantOptions {}
const base = css({
display: 'inline-flex',
width: 'fit-content',
flexShrink: 0,
alignItems: 'center',
justifyContent: 'center',
gap: '0.25rem',
overflow: 'hidden',
borderRadius: '9999px',
borderWidth: '1px',
borderColor: 'transparent',
paddingInline: '0.5rem',
paddingBlock: '0.125rem',
fontSize: '0.75rem',
lineHeight: 'calc(1 / 0.75)',
fontWeight: 500,
whiteSpace: 'nowrap',
transitionProperty: 'color, box-shadow',
transitionTimingFunction: 'cubic-bezier(0.4, 0, 0.2, 1)',
transitionDuration: '150ms',
boxShadow: 'var(--tw-ring-shadow), var(--tw-shadow)',
'&:focus-visible': {
borderColor: 'var(--ring)',
'--tw-ring-shadow':
'0 0 0 3px var(--tw-ring-color, color-mix(in oklab, var(--ring) 50%, transparent))',
},
'&[aria-invalid="true"]': {
borderColor: 'var(--destructive)',
'--tw-ring-color': 'color-mix(in oklab, var(--destructive) 20%, transparent)',
},
'.dark &[aria-invalid="true"]': {
'--tw-ring-color': 'color-mix(in oklab, var(--destructive) 40%, transparent)',
},
'& > svg': { pointerEvents: 'none', width: '0.75rem', height: '0.75rem' },
})
const variants: Record<BadgeVariant, CSSMixinDescriptor> = {
default: css({
backgroundColor: 'var(--primary)',
color: 'var(--primary-foreground)',
'&:is(a):hover': { backgroundColor: 'color-mix(in oklab, var(--primary) 90%, transparent)' },
}),
secondary: css({
backgroundColor: 'var(--secondary)',
color: 'var(--secondary-foreground)',
'&:is(a):hover': { backgroundColor: 'color-mix(in oklab, var(--secondary) 90%, transparent)' },
}),
destructive: css({
backgroundColor: 'var(--destructive)',
color: 'white',
'&:focus-visible': {
'--tw-ring-color': 'color-mix(in oklab, var(--destructive) 20%, transparent)',
},
'&:is(a):hover': {
backgroundColor: 'color-mix(in oklab, var(--destructive) 90%, transparent)',
},
'.dark &': { backgroundColor: 'color-mix(in oklab, var(--destructive) 60%, transparent)' },
'.dark &:focus-visible': {
'--tw-ring-color': 'color-mix(in oklab, var(--destructive) 40%, transparent)',
},
}),
outline: css({
borderColor: 'var(--border)',
color: 'var(--foreground)',
// Re-state the base state borders: this layer's plain `border-border` would otherwise win.
'&:focus-visible': { borderColor: 'var(--ring)' },
'&[aria-invalid="true"]': { borderColor: 'var(--destructive)' },
'&:is(a):hover': { backgroundColor: 'var(--accent)', color: 'var(--accent-foreground)' },
}),
ghost: css({
'&:is(a):hover': { backgroundColor: 'var(--accent)', color: 'var(--accent-foreground)' },
}),
link: css({
color: 'var(--primary)',
textUnderlineOffset: '4px',
'&:is(a):hover': { textDecorationLine: 'underline' },
}),
}
/**
* The `badgeVariants()` of shadcn/ui. Returns a mix you can put on any element, which is how
* you render "something that looks like a badge" (shadcn's `asChild`), e.g.
* `<a href="/new" mix={badgeVariants({ variant: 'outline' })}>New</a>`.
*/
export function badgeVariants({ variant = 'default' }: BadgeVariantOptions = {}) {
return [base, variants[variant]]
}
export function Badge(handle: Handle<BadgeProps>) {
return () => {
let { variant = 'default', mix, ...props } = handle.props
return (
<span
data-slot="badge"
data-variant={variant}
{...props}
mix={[badgeVariants({ variant }), mix]}
/>
)
}
}Update the import paths to match your project setup.
Usage
import { Badge } from '#app/ui/badge.tsx'<Badge variant="default | outline | secondary | destructive">Badge</Badge>Examples
Destructive
Destructive
import { Badge } from '#app/ui/badge.tsx'
export function BadgeDestructive() {
return () => <Badge variant="destructive">Destructive</Badge>
}import { Badge } from '#app/ui/badge.tsx'
export function BadgeDestructive() {
return () => <Badge variant="destructive">Destructive</Badge>
}Outline
Outline
import { Badge } from '#app/ui/badge.tsx'
export function BadgeOutline() {
return () => <Badge variant="outline">Outline</Badge>
}import { Badge } from '#app/ui/badge.tsx'
export function BadgeOutline() {
return () => <Badge variant="outline">Outline</Badge>
}Secondary
Secondary
import { Badge } from '#app/ui/badge.tsx'
export function BadgeSecondary() {
return () => <Badge variant="secondary">Secondary</Badge>
}import { Badge } from '#app/ui/badge.tsx'
export function BadgeSecondary() {
return () => <Badge variant="secondary">Secondary</Badge>
}API Reference
Badge
| Prop | Type | Default |
|---|---|---|
variant | BadgeVariant | "default" |
mix | MixValue | - |