Badge Components
Status badges, notification dots, and label badges built with TailwindCSS. Perfect for notifications, labels, status indicators, and UI elements. Copy, paste, and customize for React, Vue, or HTML.
1. Simple Status Badge
Clean status badges with different colors for various states and conditions.
Active
Inactive
Pending
New
Draft
<span class="inline-block bg-green-500 text-white text-xs font-bold px-3 py-1 rounded-full">Active</span>
<span class="inline-block bg-red-500 text-white text-xs font-bold px-3 py-1 rounded-full">Inactive</span>
<span class="inline-block bg-yellow-500 text-black text-xs font-bold px-3 py-1 rounded-full">Pending</span>
<span class="inline-block bg-blue-500 text-white text-xs font-bold px-3 py-1 rounded-full">New</span>
<span class="inline-block bg-gray-400 text-white text-xs font-bold px-3 py-1 rounded-full">Draft</span>
<template>
<span :class="badgeClasses">{{ status }}</span>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({
status: {
type: String,
required: true
},
variant: {
type: String,
default: 'active',
validator: (value) => ['active', 'inactive', 'pending', 'new', 'draft'].includes(value)
}
})
const badgeClasses = computed(() => {
const baseClasses = 'inline-block text-xs font-bold px-3 py-1 rounded-full'
const variantClasses = {
active: 'bg-green-500 text-white',
inactive: 'bg-red-500 text-white',
pending: 'bg-yellow-500 text-black',
new: 'bg-blue-500 text-white',
draft: 'bg-gray-400 text-white'
}
return `${baseClasses} ${variantClasses[props.variant]}`
})
</script>
import React from 'react'
const StatusBadge = ({ status, variant = 'active' }) => {
const getVariantClasses = (variant) => {
const variants = {
active: 'bg-green-500 text-white',
inactive: 'bg-red-500 text-white',
pending: 'bg-yellow-500 text-black',
new: 'bg-blue-500 text-white',
draft: 'bg-gray-400 text-white'
}
return variants[variant] || variants.active
}
return (
<span className={`inline-block text-xs font-bold px-3 py-1 rounded-full ${getVariantClasses(variant)}`}>
{status}
</span>
)
}
export default StatusBadge
2. Notification Badge
Small notification dots and count badges for buttons, icons, and menu items.
<!-- Simple notification dot -->
<div class="relative">
<button class="relative px-4 py-2 bg-violet text-white rounded-lg font-bold">
Inbox
<span class="absolute -top-1 -right-1 w-3 h-3 bg-red-500 rounded-full border-2 border-white"></span>
</button>
</div>
<!-- Notification with count -->
<div class="relative">
<button class="relative px-4 py-2 bg-gray-200 text-black rounded-lg font-bold">
Messages
<span class="absolute -top-2 -right-2 min-w-[1.5rem] h-6 bg-red-500 text-white text-xs font-bold rounded-full flex items-center justify-center border-2 border-white">12</span>
</button>
</div>
<!-- Large count -->
<div class="relative">
<button class="relative px-4 py-2 bg-blue-500 text-white rounded-lg font-bold">
Notifications
<span class="absolute -top-2 -right-2 min-w-[1.5rem] h-6 bg-orange-500 text-white text-xs font-bold rounded-full flex items-center justify-center border-2 border-white">99+</span>
</button>
</div>
<template>
<div class="relative">
<button :class="buttonClass">
{{ label }}
<span v-if="showBadge" :class="badgeClass">
{{ badgeText }}
</span>
</button>
</div>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({
label: {
type: String,
required: true
},
count: {
type: Number,
default: 0
},
showDot: {
type: Boolean,
default: false
},
variant: {
type: String,
default: 'violet'
}
})
const showBadge = computed(() => props.count > 0 || props.showDot)
const badgeText = computed(() => {
if (props.showDot && props.count === 0) return ''
return props.count > 99 ? '99+' : props.count.toString()
})
const buttonClass = computed(() => {
const variants = {
violet: 'bg-violet text-white',
gray: 'bg-gray-200 text-black',
blue: 'bg-blue-500 text-white'
}
return `relative px-4 py-2 rounded-lg font-bold ${variants[props.variant]}`
})
const badgeClass = computed(() => {
const baseClass = 'absolute border-2 border-white'
if (props.showDot && props.count === 0) {
return `${baseClass} -top-1 -right-1 w-3 h-3 bg-red-500 rounded-full`
}
return `${baseClass} -top-2 -right-2 min-w-[1.5rem] h-6 bg-red-500 text-white text-xs font-bold rounded-full flex items-center justify-center`
})
</script>
import React from 'react'
const NotificationBadge = ({ label, count = 0, showDot = false, variant = 'violet' }) => {
const showBadge = count > 0 || showDot
const badgeText = showDot && count === 0 ? '' : count > 99 ? '99+' : count.toString()
const getButtonClass = (variant) => {
const variants = {
violet: 'bg-violet text-white',
gray: 'bg-gray-200 text-black',
blue: 'bg-blue-500 text-white'
}
return `relative px-4 py-2 rounded-lg font-bold ${variants[variant]}`
}
const getBadgeClass = () => {
const baseClass = 'absolute border-2 border-white'
if (showDot && count === 0) {
return `${baseClass} -top-1 -right-1 w-3 h-3 bg-red-500 rounded-full`
}
return `${baseClass} -top-2 -right-2 min-w-[1.5rem] h-6 bg-red-500 text-white text-xs font-bold rounded-full flex items-center justify-center`
}
return (
<div className="relative">
<button className={getButtonClass(variant)}>
{label}
{showBadge && (
<span className={getBadgeClass()}>
{badgeText}
</span>
)}
</button>
</div>
)
}
export default NotificationBadge
3. Neobrutalist Badge
Bold brutalist-style badges with thick borders and strong shadows for modern designs.
PRO
FREE
SALE
NEW
HOT
<span class="inline-block bg-[#ffde59] text-black text-xs font-black px-4 py-2 border-2 border-black shadow-[3px_3px_0px_0px_rgba(0,0,0,1)] transform hover:-translate-x-1 hover:-translate-y-1 hover:shadow-[4px_4px_0px_0px_rgba(0,0,0,1)] transition-all uppercase tracking-wide">PRO</span>
<span class="inline-block bg-violet text-white text-xs font-black px-4 py-2 border-2 border-black shadow-[3px_3px_0px_0px_rgba(0,0,0,1)] transform hover:-translate-x-1 hover:-translate-y-1 hover:shadow-[4px_4px_0px_0px_rgba(0,0,0,1)] transition-all uppercase tracking-wide">FREE</span>
<span class="inline-block bg-[#ff5c5c] text-white text-xs font-black px-4 py-2 border-2 border-black shadow-[3px_3px_0px_0px_rgba(0,0,0,1)] transform hover:-translate-x-1 hover:-translate-y-1 hover:shadow-[4px_4px_0px_0px_rgba(0,0,0,1)] transition-all uppercase tracking-wide">SALE</span>
<span class="inline-block bg-green-500 text-white text-xs font-black px-4 py-2 border-2 border-black shadow-[3px_3px_0px_0px_rgba(0,0,0,1)] transform hover:-translate-x-1 hover:-translate-y-1 hover:shadow-[4px_4px_0px_0px_rgba(0,0,0,1)] transition-all uppercase tracking-wide">NEW</span>
<span class="inline-block bg-blue-500 text-white text-xs font-black px-4 py-2 border-2 border-black shadow-[3px_3px_0px_0px_rgba(0,0,0,1)] transform hover:-translate-x-1 hover:-translate-y-1 hover:shadow-[4px_4px_0px_0px_rgba(0,0,0,1)] transition-all uppercase tracking-wide">HOT</span>
<template>
<span :class="badgeClasses">{{ label }}</span>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({
label: {
type: String,
required: true
},
variant: {
type: String,
default: 'yellow',
validator: (value) => ['yellow', 'violet', 'red', 'green', 'blue'].includes(value)
}
})
const badgeClasses = computed(() => {
const baseClasses = 'inline-block text-xs font-black px-4 py-2 border-2 border-black shadow-[3px_3px_0px_0px_rgba(0,0,0,1)] transform hover:-translate-x-1 hover:-translate-y-1 hover:shadow-[4px_4px_0px_0px_rgba(0,0,0,1)] transition-all uppercase tracking-wide'
const variantClasses = {
yellow: 'bg-[#ffde59] text-black',
violet: 'bg-violet text-white',
red: 'bg-[#ff5c5c] text-white',
green: 'bg-green-500 text-white',
blue: 'bg-blue-500 text-white'
}
return `${baseClasses} ${variantClasses[props.variant]}`
})
</script>
import React from 'react'
const NeobrutalistBadge = ({ label, variant = 'yellow' }) => {
const getVariantClasses = (variant) => {
const variants = {
yellow: 'bg-[#ffde59] text-black',
violet: 'bg-violet text-white',
red: 'bg-[#ff5c5c] text-white',
green: 'bg-green-500 text-white',
blue: 'bg-blue-500 text-white'
}
return variants[variant] || variants.yellow
}
const baseClasses = 'inline-block text-xs font-black px-4 py-2 border-2 border-black shadow-[3px_3px_0px_0px_rgba(0,0,0,1)] transform hover:-translate-x-1 hover:-translate-y-1 hover:shadow-[4px_4px_0px_0px_rgba(0,0,0,1)] transition-all uppercase tracking-wide'
return (
<span className={`${baseClasses} ${getVariantClasses(variant)}`}>
{label}
</span>
)
}
export default NeobrutalistBadge
4. Icon Badge
Badges with icons for enhanced visual communication and better UX.
Verified
Warning
Error
Info
<span class="inline-flex items-center gap-1 bg-green-500 text-white text-xs font-bold px-3 py-1 rounded-full">
<svg class="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"/>
</svg>
Verified
</span>
<span class="inline-flex items-center gap-1 bg-orange-500 text-white text-xs font-bold px-3 py-1 rounded-full">
<svg class="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd"/>
</svg>
Warning
</span>
<span class="inline-flex items-center gap-1 bg-red-500 text-white text-xs font-bold px-3 py-1 rounded-full">
<svg class="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd"/>
</svg>
Error
</span>
<span class="inline-flex items-center gap-1 bg-blue-500 text-white text-xs font-bold px-3 py-1 rounded-full">
<svg class="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"/>
</svg>
Info
</span>
<template>
<span :class="badgeClasses">
<svg v-if="showIcon" class="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
<path :d="iconPath" :fill-rule="iconFillRule" :clip-rule="iconClipRule"/>
</svg>
{{ label }}
</span>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({
label: {
type: String,
required: true
},
variant: {
type: String,
default: 'success',
validator: (value) => ['success', 'warning', 'error', 'info'].includes(value)
},
showIcon: {
type: Boolean,
default: true
}
})
const badgeClasses = computed(() => {
const baseClasses = 'inline-flex items-center gap-1 text-xs font-bold px-3 py-1 rounded-full'
const variantClasses = {
success: 'bg-green-500 text-white',
warning: 'bg-orange-500 text-white',
error: 'bg-red-500 text-white',
info: 'bg-blue-500 text-white'
}
return `${baseClasses} ${variantClasses[props.variant]}`
})
const iconPath = computed(() => {
const paths = {
success: 'M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z',
warning: 'M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z',
error: 'M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z',
info: 'M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z'
}
return paths[props.variant]
})
const iconFillRule = computed(() => 'evenodd')
const iconClipRule = computed(() => 'evenodd')
</script>
import React from 'react'
const IconBadge = ({ label, variant = 'success', showIcon = true }) => {
const getVariantClasses = (variant) => {
const variants = {
success: 'bg-green-500 text-white',
warning: 'bg-orange-500 text-white',
error: 'bg-red-500 text-white',
info: 'bg-blue-500 text-white'
}
return variants[variant] || variants.success
}
const getIconPath = (variant) => {
const paths = {
success: 'M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z',
warning: 'M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z',
error: 'M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z',
info: 'M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z'
}
return paths[variant] || paths.success
}
const baseClasses = 'inline-flex items-center gap-1 text-xs font-bold px-3 py-1 rounded-full'
return (
<span className={`${baseClasses} ${getVariantClasses(variant)}`}>
{showIcon && (
<svg className="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d={getIconPath(variant)} clipRule="evenodd" />
</svg>
)}
{label}
</span>
)
}
export default IconBadge
5. Size Variations
Different badge sizes from extra small to extra large for various use cases.
XS
Small
Medium
Large
XL
<!-- Extra Small -->
<span class="inline-block bg-violet text-white text-xs font-bold px-2 py-0.5 rounded-full">XS</span>
<!-- Small -->
<span class="inline-block bg-violet text-white text-xs font-bold px-3 py-1 rounded-full">Small</span>
<!-- Medium -->
<span class="inline-block bg-violet text-white text-sm font-bold px-4 py-1.5 rounded-full">Medium</span>
<!-- Large -->
<span class="inline-block bg-violet text-white text-base font-bold px-5 py-2 rounded-full">Large</span>
<!-- Extra Large -->
<span class="inline-block bg-violet text-white text-lg font-bold px-6 py-2.5 rounded-full">XL</span>
<template>
<span :class="badgeClasses">{{ label }}</span>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({
label: {
type: String,
required: true
},
size: {
type: String,
default: 'medium',
validator: (value) => ['xs', 'small', 'medium', 'large', 'xl'].includes(value)
},
variant: {
type: String,
default: 'violet'
}
})
const badgeClasses = computed(() => {
const baseClasses = 'inline-block font-bold rounded-full'
const sizeClasses = {
xs: 'text-xs px-2 py-0.5',
small: 'text-xs px-3 py-1',
medium: 'text-sm px-4 py-1.5',
large: 'text-base px-5 py-2',
xl: 'text-lg px-6 py-2.5'
}
const variantClasses = {
violet: 'bg-violet text-white',
green: 'bg-green-500 text-white',
red: 'bg-red-500 text-white',
blue: 'bg-blue-500 text-white',
gray: 'bg-gray-400 text-white'
}
return `${baseClasses} ${sizeClasses[props.size]} ${variantClasses[props.variant]}`
})
</script>
import React from 'react'
const SizeBadge = ({ label, size = 'medium', variant = 'violet' }) => {
const getSizeClasses = (size) => {
const sizeMap = {
xs: 'text-xs px-2 py-0.5',
small: 'text-xs px-3 py-1',
medium: 'text-sm px-4 py-1.5',
large: 'text-base px-5 py-2',
xl: 'text-lg px-6 py-2.5'
}
return sizeMap[size] || sizeMap.medium
}
const getVariantClasses = (variant) => {
const variants = {
violet: 'bg-violet text-white',
green: 'bg-green-500 text-white',
red: 'bg-red-500 text-white',
blue: 'bg-blue-500 text-white',
gray: 'bg-gray-400 text-white'
}
return variants[variant] || variants.violet
}
const baseClasses = 'inline-block font-bold rounded-full'
return (
<span className={`${baseClasses} ${getSizeClasses(size)} ${getVariantClasses(variant)}`}>
{label}
</span>
)
}
export default SizeBadge
6. Outline Badge
Badges with outlined borders for a subtle, modern look.
Outline
Success
Error
Info
Neutral
<span class="inline-block border border-violet text-violet text-xs font-bold px-3 py-1 rounded-full">Outline</span>
<span class="inline-block border border-green-500 text-green-500 text-xs font-bold px-3 py-1 rounded-full">Success</span>
<span class="inline-block border border-red-500 text-red-500 text-xs font-bold px-3 py-1 rounded-full">Error</span>
<span class="inline-block border border-blue-500 text-blue-500 text-xs font-bold px-3 py-1 rounded-full">Info</span>
<span class="inline-block border border-gray-400 text-gray-500 text-xs font-bold px-3 py-1 rounded-full">Neutral</span>
<template>
<span :class="badgeClasses">{{ label }}</span>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({
label: String,
variant: {
type: String,
default: 'outline',
validator: (value) => ['outline', 'success', 'error', 'info', 'neutral'].includes(value)
}
})
const badgeClasses = computed(() => {
const base = 'inline-block border text-xs font-bold px-3 py-1 rounded-full'
const variants = {
outline: 'border-violet text-violet',
success: 'border-green-500 text-green-500',
error: 'border-red-500 text-red-500',
info: 'border-blue-500 text-blue-500',
neutral: 'border-gray-400 text-gray-500'
}
return `${base} ${variants[props.variant]}`
})
</script>
import React from 'react'
const OutlineBadge = ({ label, variant = 'outline' }) => {
const getVariantClasses = (variant) => {
const variants = {
outline: 'border-violet text-violet',
success: 'border-green-500 text-green-500',
error: 'border-red-500 text-red-500',
info: 'border-blue-500 text-blue-500',
neutral: 'border-gray-400 text-gray-500'
}
return variants[variant] || variants.outline
}
return (
<span className={`inline-block border text-xs font-bold px-3 py-1 rounded-full ${getVariantClasses(variant)}`}>
{label}
</span>
)
}
export default OutlineBadge