Skip to content

Badge

Badge provides a versatile solution for displaying status indicators, labels, and notifications with built-in animations, multiple styling variants, and flexible composition. It supports animated transitions and customizable visual feedback.

import { Badge, BadgeText, BadgeIcon } from 'rnc-theme';
<Badge>
<BadgeText>New</BadgeText>
</Badge>
PropTypeDefaultDescription
variantBadgeVariant'default'Visual style variant
sizeBadgeSize'md'Badge size (xs, sm, md, lg)
roundedbooleantrueApply rounded corners
animatedbooleantrueEnable animations
scalenumber1Scale factor for animation
fadeInbooleantrueEnable fade-in animation
styleStyleProp<ViewStyle>-Additional container styles
PropTypeDefaultDescription
childrenReact.ReactNode-Text content to display
styleTextStyle-Additional text styles
PropTypeDefaultDescription
childrenReact.ReactNode-Icon component to render
position'left' | 'right''left'Icon position relative to text
styleStyleProp<ViewStyle>-Additional icon container styles
VariantDescriptionUse Case
defaultDefault neutral badgeGeneral labels, categories
primaryPrimary brand badgeImportant status, highlights
secondarySecondary brand badgeAlternative status indicators
successSuccess state badgeCompleted, verified, active states
warningWarning state badgePending, caution states
errorError/danger badgeFailed, critical states
outlineOutlined transparent badgeSubtle status indicators
filledFilled surface badgeStandard status labels
ghostTransparent badgeMinimal status indicators
infoInformation badgeInformational states
destructiveDestructive action badgeDelete, remove indicators
SizeDescriptionUse Case
xsExtra smallNotification dots, counters
smSmallCompact status indicators
mdMediumStandard badges
lgLargeProminent status displays
<HStack spacing="md" align="center">
<Badge variant="success">
<BadgeIcon position="left">
<CheckIcon size={12} />
</BadgeIcon>
<BadgeText>Active</BadgeText>
</Badge>
<Badge variant="warning">
<BadgeIcon position="left">
<ClockIcon size={12} />
</BadgeIcon>
<BadgeText>Pending</BadgeText>
</Badge>
<Badge variant="error">
<BadgeIcon position="left">
<XIcon size={12} />
</BadgeIcon>
<BadgeText>Failed</BadgeText>
</Badge>
<Badge variant="info">
<BadgeIcon position="left">
<InfoIcon size={12} />
</BadgeIcon>
<BadgeText>Draft</BadgeText>
</Badge>
</HStack>
<VStack spacing="md" align="flex-start">
<Badge size="xs" variant="primary">
<BadgeText>XS</BadgeText>
</Badge>
<Badge size="sm" variant="primary">
<BadgeText>Small</BadgeText>
</Badge>
<Badge size="md" variant="primary">
<BadgeText>Medium</BadgeText>
</Badge>
<Badge size="lg" variant="primary">
<BadgeText>Large</BadgeText>
</Badge>
</VStack>
<HStack spacing="lg" align="center">
{/* Simple counter */}
<View style={{ position: 'relative' }}>
<BellIcon size={24} />
<Badge
variant="error"
size="xs"
style={{
position: 'absolute',
top: -8,
right: -8,
minWidth: 20,
height: 20
}}
>
<BadgeText>5</BadgeText>
</Badge>
</View>
{/* Message indicator */}
<View style={{ position: 'relative' }}>
<MessageIcon size={24} />
<Badge
variant="success"
size="xs"
style={{
position: 'absolute',
top: -4,
right: -4
}}
>
<BadgeText>New</BadgeText>
</Badge>
</View>
{/* Activity dot */}
<View style={{ position: 'relative' }}>
<Avatar source={{ uri: 'user-avatar.jpg' }} />
<Badge
variant="success"
size="xs"
style={{
position: 'absolute',
bottom: 2,
right: 2,
width: 12,
height: 12
}}
/>
</View>
</HStack>
<ScrollView horizontal showsHorizontalScrollIndicator={false}>
<HStack spacing="sm" padding="md">
<Badge variant="outline">
<BadgeText>Technology</BadgeText>
</Badge>
<Badge variant="outline">
<BadgeText>Design</BadgeText>
</Badge>
<Badge variant="outline">
<BadgeText>Business</BadgeText>
</Badge>
<Badge variant="outline">
<BadgeText>Marketing</BadgeText>
</Badge>
<Badge variant="outline">
<BadgeText>Development</BadgeText>
</Badge>
</HStack>
</ScrollView>
const UserProfile = ({ user }) => {
const getRoleBadge = (role) => {
switch (role) {
case 'admin':
return {
variant: 'destructive',
icon: <ShieldIcon size={12} />,
text: 'Admin'
};
case 'moderator':
return {
variant: 'warning',
icon: <StarIcon size={12} />,
text: 'Moderator'
};
case 'premium':
return {
variant: 'primary',
icon: <CrownIcon size={12} />,
text: 'Premium'
};
case 'verified':
return {
variant: 'success',
icon: <CheckIcon size={12} />,
text: 'Verified'
};
default:
return null;
}
};
const roleBadge = getRoleBadge(user.role);
return (
<HStack spacing="md" align="center">
<Avatar source={{ uri: user.avatar }} />
<VStack spacing="xs">
<HStack spacing="sm" align="center">
<Text style={{ fontWeight: '600' }}>{user.name}</Text>
{roleBadge && (
<Badge variant={roleBadge.variant} size="sm">
<BadgeIcon position="left">
{roleBadge.icon}
</BadgeIcon>
<BadgeText>{roleBadge.text}</BadgeText>
</Badge>
)}
</HStack>
<Text style={{ color: 'gray' }}>@{user.username}</Text>
</VStack>
</HStack>
);
};
const ProductCard = ({ product }) => {
return (
<Card>
<View style={{ position: 'relative' }}>
<Image source={{ uri: product.image }} style={styles.productImage} />
{/* Discount Badge */}
{product.discount && (
<Badge
variant="error"
size="sm"
style={{
position: 'absolute',
top: 8,
left: 8
}}
>
<BadgeText>-{product.discount}%</BadgeText>
</Badge>
)}
{/* Stock Status */}
{product.stock < 5 && (
<Badge
variant="warning"
size="xs"
style={{
position: 'absolute',
top: 8,
right: 8
}}
>
<BadgeText>Low Stock</BadgeText>
</Badge>
)}
{/* New Product */}
{product.isNew && (
<Badge
variant="success"
size="sm"
style={{
position: 'absolute',
bottom: 8,
left: 8
}}
>
<BadgeIcon position="left">
<SparkleIcon size={12} />
</BadgeIcon>
<BadgeText>New</BadgeText>
</Badge>
)}
</View>
<VStack spacing="sm" padding="md">
<HStack spacing="sm" align="center" justify="space-between">
<Text style={{ fontWeight: '600' }}>{product.name}</Text>
{/* Rating Badge */}
<Badge variant="filled" size="sm">
<BadgeIcon position="left">
<StarIcon size={12} />
</BadgeIcon>
<BadgeText>{product.rating}</BadgeText>
</Badge>
</HStack>
<HStack spacing="sm" align="center">
<Text style={{ fontSize: 18, fontWeight: 'bold' }}>
${product.price}
</Text>
{/* Free Shipping */}
{product.freeShipping && (
<Badge variant="info" size="xs">
<BadgeText>Free Ship</BadgeText>
</Badge>
)}
</HStack>
{/* Category Tags */}
<HStack spacing="xs" wrap>
{product.categories.map((category, index) => (
<Badge key={index} variant="ghost" size="xs">
<BadgeText>{category}</BadgeText>
</Badge>
))}
</HStack>
</VStack>
</Card>
);
};
const OrderTimeline = ({ order }) => {
const getStatusBadge = (status, isActive) => {
const config = {
ordered: { variant: 'success', text: 'Ordered' },
processing: { variant: 'warning', text: 'Processing' },
shipped: { variant: 'info', text: 'Shipped' },
delivered: { variant: 'success', text: 'Delivered' }
};
const statusConfig = config[status];
return (
<Badge
variant={isActive ? statusConfig.variant : 'outline'}
size="sm"
animated={isActive}
scale={isActive ? 1.05 : 1}
>
<BadgeText>{statusConfig.text}</BadgeText>
</Badge>
);
};
return (
<VStack spacing="lg" padding="lg">
<Text style={{ fontSize: 18, fontWeight: '600' }}>
Order #{order.id}
</Text>
<HStack spacing="md" align="center" justify="space-between">
{['ordered', 'processing', 'shipped', 'delivered'].map((status, index) => (
<VStack key={status} spacing="xs" align="center">
{getStatusBadge(status, order.currentStatus === status)}
<Text style={{ fontSize: 12, color: 'gray' }}>
{order.timestamps[status]}
</Text>
</VStack>
))}
</HStack>
</VStack>
);
};
const AnimatedCounter = ({ count, maxCount = 99 }) => {
const [displayCount, setDisplayCount] = useState(0);
useEffect(() => {
const timer = setTimeout(() => {
setDisplayCount(count);
}, 100);
return () => clearTimeout(timer);
}, [count]);
const displayText = displayCount > maxCount ? `${maxCount}+` : displayCount.toString();
return (
<Badge
variant="error"
size="xs"
animated={true}
scale={displayCount > 0 ? 1 : 0}
fadeIn={true}
style={{
transform: [{ scale: displayCount > 0 ? 1 : 0 }]
}}
>
<BadgeText>{displayText}</BadgeText>
</Badge>
);
};
const DynamicStatusBadge = ({ status, lastUpdated }) => {
const [isBlinking, setIsBlinking] = useState(false);
useEffect(() => {
if (status === 'processing') {
const interval = setInterval(() => {
setIsBlinking(prev => !prev);
}, 1000);
return () => clearInterval(interval);
}
}, [status]);
const getStatusConfig = () => {
switch (status) {
case 'online':
return { variant: 'success', text: 'Online', icon: <CircleIcon /> };
case 'offline':
return { variant: 'error', text: 'Offline', icon: <CircleIcon /> };
case 'processing':
return { variant: 'warning', text: 'Processing', icon: <LoaderIcon /> };
case 'idle':
return { variant: 'info', text: 'Idle', icon: <PauseIcon /> };
default:
return { variant: 'default', text: 'Unknown', icon: <QuestionIcon /> };
}
};
const config = getStatusConfig();
return (
<Badge
variant={config.variant}
size="sm"
animated={true}
scale={isBlinking ? 1.1 : 1}
style={{
opacity: status === 'processing' && isBlinking ? 0.7 : 1
}}
>
<BadgeIcon position="left">
{config.icon}
</BadgeIcon>
<BadgeText>{config.text}</BadgeText>
</Badge>
);
};
const ThemedBadgeSet = () => {
const { theme } = useTheme();
const customBadgeStyle = {
backgroundColor: theme.colors.surface + '20',
borderColor: theme.colors.primary,
borderWidth: 2
};
return (
<VStack spacing="md">
<Badge style={customBadgeStyle} rounded={false}>
<BadgeText style={{ color: theme.colors.primary }}>
Custom Theme
</BadgeText>
</Badge>
<Badge
variant="ghost"
style={{
backgroundColor: 'linear-gradient(45deg, #FF6B6B, #4ECDC4)',
borderRadius: 20
}}
>
<BadgeText style={{ color: 'white' }}>Gradient</BadgeText>
</Badge>
</VStack>
);
};
const [scale, setScale] = useState(1);
<Badge
variant="primary"
animated={true}
scale={scale}
onPress={() => setScale(scale === 1 ? 1.2 : 1)}
>
<BadgeText>Scale Me</BadgeText>
</Badge>

Visual Hierarchy

  • Use color-coded variants to indicate status clearly (success for positive, error for negative)
  • Keep badge text concise - prefer single words or short phrases
  • Position badges consistently across your application for predictable user experience

Content Guidelines

  • Use title case for category tags and sentence case for status indicators
  • Avoid using badges for lengthy text content
  • Consider internationalization when designing badge content

Performance

  • Use React.memo for badge components that render frequently
  • Minimize animated badges on screens with many items
  • Consider virtualization for long lists containing badges