# Indicator Indicator component for adding badges, status markers, or notifications to elements. Perfect for showing counts, online status, or alerts. ## Tag `Indicator` ## Props | Prop | Type | Default | Description | | :----------- | :--------------------------- | :---------- | :----------------------------------------------- | | `badge` | `string \| VNode \| Signal` | `-` | Content to display as indicator | | `badgeClass` | `string` | `''` | Additional CSS classes for the badge | | `class` | `string` | `''` | Additional CSS classes for the container | | `children` | `VNode` | `-` | Element to attach the indicator to | ## Live Examples ### Basic Indicator

Live Demo

```javascript const BasicDemo = () => { return Div({ class: 'flex flex-wrap gap-8 justify-center' }, [ Indicator({ badge: '3', badgeClass: 'badge-primary' }, [ Div({ class: 'w-16 h-16 bg-base-300 rounded-lg flex items-center justify-center' }, '📦') ]), Indicator({ badge: '99+', badgeClass: 'badge-secondary' }, [ Div({ class: 'w-16 h-16 bg-base-300 rounded-lg flex items-center justify-center' }, '🔔') ]), Indicator({ badge: 'New', badgeClass: 'badge-accent' }, [ Div({ class: 'w-16 h-16 bg-base-300 rounded-lg flex items-center justify-center' }, '✨') ]) ]); }; Mount(BasicDemo, '#demo-basic'); ``` ### Online Status Indicator

Live Demo

```javascript const StatusDemo = () => { return Div({ class: 'flex flex-wrap gap-8 justify-center' }, [ Indicator({ badge: '●', badgeClass: 'badge-success badge-xs' }, [ Div({ class: 'avatar placeholder' }, [ Div({ class: 'bg-neutral text-neutral-content rounded-full w-12 h-12 flex items-center justify-center' }, 'JD') ]) ]), Indicator({ badge: '●', badgeClass: 'badge-warning badge-xs' }, [ Div({ class: 'avatar placeholder' }, [ Div({ class: 'bg-neutral text-neutral-content rounded-full w-12 h-12 flex items-center justify-center' }, 'JS') ]) ]), Indicator({ badge: '●', badgeClass: 'badge-error badge-xs' }, [ Div({ class: 'avatar placeholder' }, [ Div({ class: 'bg-neutral text-neutral-content rounded-full w-12 h-12 flex items-center justify-center' }, 'BC') ]) ]) ]); }; Mount(StatusDemo, '#demo-status'); ``` ### Reactive Counter

Live Demo

```javascript const ReactiveDemo = () => { const count = $(0); return Div({ class: 'flex flex-col gap-4 items-center' }, [ Indicator({ badge: () => count() > 0 ? count() : null, badgeClass: 'badge-primary' }, [ Button({ class: 'btn btn-lg btn-primary', onclick: () => count(count() + 1) }, 'Notifications') ]), Div({ class: 'flex gap-2' }, [ Button({ class: 'btn btn-sm', onclick: () => count(Math.max(0, count() - 1)) }, 'Decrease'), Button({ class: 'btn btn-sm btn-ghost', onclick: () => count(0) }, 'Clear') ]) ]); }; Mount(ReactiveDemo, '#demo-reactive'); ``` ### Shopping Cart

Live Demo

```javascript const CartDemo = () => { const cart = $([ { id: 1, name: 'Product 1', price: 29 }, { id: 2, name: 'Product 2', price: 49 } ]); const addItem = () => { const newId = Math.max(...cart().map(i => i.id), 0) + 1; cart([...cart(), { id: newId, name: `Product ${newId}`, price: Math.floor(Math.random() * 100) + 10 }]); Toast('Item added to cart', 'alert-success', 1500); }; const removeItem = (id) => { cart(cart().filter(item => item.id !== id)); Toast('Item removed', 'alert-info', 1500); }; const total = () => cart().reduce((sum, item) => sum + item.price, 0); return Div({ class: 'flex flex-col gap-4' }, [ Div({ class: 'flex justify-between items-center' }, [ Indicator({ badge: () => cart().length, badgeClass: 'badge-primary' }, [ Button({ class: 'btn', onclick: addItem }, '🛒 Add to Cart') ]), Span({ class: 'text-lg font-bold' }, () => `Total: $${total()}`) ]), cart().length === 0 ? Div({ class: 'alert alert-soft text-center' }, 'Cart is empty') : Div({ class: 'flex flex-col gap-2' }, cart().map(item => Div({ class: 'flex justify-between items-center p-2 bg-base-200 rounded-lg' }, [ Span({}, item.name), Div({ class: 'flex gap-2 items-center' }, [ Span({ class: 'text-sm font-bold' }, `$${item.price}`), Button({ class: 'btn btn-xs btn-ghost btn-circle', onclick: () => removeItem(item.id) }, '✕') ]) ]) )) ]); }; Mount(CartDemo, '#demo-cart'); ``` ### Email Inbox

Live Demo

```javascript const InboxDemo = () => { const unread = $(3); const messages = $([ { id: 1, from: 'john@example.com', subject: 'Meeting tomorrow', read: false }, { id: 2, from: 'jane@example.com', subject: 'Project update', read: false }, { id: 3, from: 'bob@example.com', subject: 'Question about design', read: false }, { id: 4, from: 'alice@example.com', subject: 'Weekly report', read: true } ]); const markAsRead = (id) => { const msg = messages().find(m => m.id === id); if (!msg.read) { msg.read = true; messages([...messages()]); unread(unread() - 1); } }; return Div({ class: 'flex flex-col gap-4' }, [ Div({ class: 'flex justify-between items-center' }, [ Indicator({ badge: () => unread(), badgeClass: 'badge-primary' }, [ Span({ class: 'text-lg font-bold' }, 'Inbox') ]), Button({ class: 'btn btn-sm btn-ghost', onclick: () => { messages().forEach(m => m.read = true); messages([...messages()]); unread(0); } }, 'Mark all read') ]), Div({ class: 'flex flex-col gap-2' }, messages().map(msg => Div({ class: `p-3 rounded-lg cursor-pointer transition-all ${msg.read ? 'bg-base-200 opacity-60' : 'bg-primary/10 border-l-4 border-primary'}`, onclick: () => markAsRead(msg.id) }, [ Div({ class: 'font-medium' }, msg.from), Div({ class: 'text-sm' }, msg.subject), !msg.read && Span({ class: 'badge badge-xs badge-primary mt-1' }, 'New') ]) )) ]); }; Mount(InboxDemo, '#demo-inbox'); ``` ### Custom Position

Live Demo

```javascript const PositionsDemo = () => { return Div({ class: 'flex flex-wrap gap-8 justify-center' }, [ Div({ class: 'text-center' }, [ Div({ class: 'text-xs mb-2' }, 'Top-Left'), Indicator({ badge: '●', badgeClass: 'badge-success badge-xs' }, [ Div({ class: 'w-12 h-12 bg-base-300 rounded-lg' }) ]) ]), Div({ class: 'text-center' }, [ Div({ class: 'text-xs mb-2' }, 'Top-Right'), Indicator({ badge: '●', badgeClass: 'badge-success badge-xs' }, [ Div({ class: 'w-12 h-12 bg-base-300 rounded-lg' }) ]) ]), Div({ class: 'text-center' }, [ Div({ class: 'text-xs mb-2' }, 'Bottom-Left'), Indicator({ badge: '●', badgeClass: 'badge-success badge-xs' }, [ Div({ class: 'w-12 h-12 bg-base-300 rounded-lg' }) ]) ]), Div({ class: 'text-center' }, [ Div({ class: 'text-xs mb-2' }, 'Bottom-Right'), Indicator({ badge: '●', badgeClass: 'badge-success badge-xs' }, [ Div({ class: 'w-12 h-12 bg-base-300 rounded-lg' }) ]) ]) ]); }; Mount(PositionsDemo, '#demo-positions'); ``` ### All Variants

Live Demo

```javascript const VariantsDemo = () => { return Div({ class: 'flex flex-wrap gap-8 justify-center' }, [ Indicator({ badge: '3', badgeClass: 'badge-primary badge-sm' }, [ Div({ class: 'w-12 h-12 bg-base-300 rounded-lg flex items-center justify-center' }, '📧') ]), Indicator({ badge: '99+', badgeClass: 'badge-secondary badge-md' }, [ Div({ class: 'w-12 h-12 bg-base-300 rounded-lg flex items-center justify-center' }, '🔔') ]), Indicator({ badge: '●', badgeClass: 'badge-success badge-xs' }, [ Div({ class: 'avatar' }, [ Div({ class: 'w-10 h-10 rounded-full bg-primary' }) ]) ]), Indicator({ badge: '!', badgeClass: 'badge-error badge-sm' }, [ Div({ class: 'w-12 h-12 bg-base-300 rounded-lg flex items-center justify-center' }, '⚠️') ]) ]); }; Mount(VariantsDemo, '#demo-variants'); ```