Indicator#

A wrapper that anchors a floating item to a corner or edge of whatever it wraps: the badge on the inbox button, the dot on the avatar. Two parts and no paint of its own — the root establishes the positioning box, the item declares its slot as data-placement, and the slots are logical (start / end, never left / right) so a recipe positions with inset-inline-* and RTL mirrors for free.

Import#

TSX
import { Indicator } from '@sigx/zero/indicator';

Indicator is a compound: Indicator.Root, Indicator.Item. It is also re-exported from the @sigx/zero root, together with indicatorAnatomy. The IndicatorPlacement type — the union of the eight slots — is exported alongside IndicatorRootProps and IndicatorItemProps.

Usage#

TSX
import { component } from 'sigx';
import { Indicator } from '@sigx/zero/indicator';
import { Badge } from '@sigx/zero/badge';
import { Button } from '@sigx/zero/button';

const Inbox = component(({ signal }) => {
    const state = signal({ unread: 12 });

    return () => (
        <Indicator.Root>
            {state.unread > 0 && (
                <Indicator.Item>
                    <Badge.Root color="error">{state.unread}</Badge.Root>
                </Indicator.Item>
            )}
            <Button.Root>Inbox</Button.Root>
        </Indicator.Root>
    );
});

Indicator takes no model: it has no state of its own. Whether the item is shown, and what it says, is the item's business — render it or leave it out. The root wraps the decorated content and the item; the item floats over the content to its declared slot.

Choosing a slot#

TSX
<Indicator.Root>
    <Indicator.Item placement="bottom-end">
        <Status.Root color="success" label="Online" />
    </Indicator.Item>
    <Avatar.Root>…</Avatar.Root>
</Indicator.Root>

placement is one of eight slots — four corners, two edge midpoints and the two bare inline sides for the middle row:

startcentreend
toptop-starttoptop-end
middlestartend
bottombottom-startbottombottom-end

The default is top-end. There is no middle-center: an item centred on its content is an overlay, not an indicator. The item always renders data-placement — including for the default — so a recipe keys every slot the same way and never needs an "absent attribute" case.

What the item means#

The indicator adds no ARIA. What the item means is the item's job: a Badge with a count announces its text, a Status dot announces its label or hides itself. Put the meaning on the content, not on the wrapper.

Anatomy#

PartElementStatesFlagsNotes
rootdivThe positioning box. Carries the variant axes.
itemspandata-placement: top-start | top | top-end | start | end | bottom-start | bottom | bottom-end. Inside root.

Every part carries data-scope="indicator" and data-part="<part>". Neither part hints a token: the indicator paints nothing, it only positions. The placement subset is contract data rather than styling — a recipe keys each slot, and the anatomy validator rejects a placement that is not one of the eight. See The anatomy contract.

Props#

Indicator.Root#

PropTypeDefaultDescription
color / size / variant / axes / modsdesign-system vocabularyThe variant axes, rendered as data-* on root.
classstringExtra classes.

The default slot holds the decorated content and the item(s). Indicator has no model, no default-value prop and no change event.

Indicator.Item#

PropTypeDefaultDescription
placementIndicatorPlacement'top-end'Which of the eight slots the item floats to; rendered as data-placement.
classstringExtra classes.

The default slot is the floating content.

In the shipped design systems#

Both @sigx/zero-basic and @sigx/zero-daisyui wire color (all eight recommended roles) and size (xsxl) on the indicator root. Neither wires a variant or any mods; under a design system's /register import those props are therefore absent. See Typed vocabulary.

An indicator recipe makes root the positioning context (position: relative, display: inline-flex or similar) and positions item absolutely by data-placement. Because every slot spells logically, the item rules use inset-inline-start / inset-inline-end with a translate to sit the item on the corner; nothing is flipped by hand for right-to-left scripts.

Badge and Status are the usual items; Avatar and Button the usual content.