Skip to content

Tracker

The tracker shows how something progresses over time: a vertical rail with an Entry per milestone, an optional Label to mark a phase, and a group of Steps branching off the rail for the work inside a milestone.

Jane Cooperleft a note
Mar 10, 2026 · 10:42 am
Please double-check the shipment packaging.
In-progress
Shipment 1
In Progress
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aliquam aperiam earum facilis fugiat in.
Carrier: Royal Mail (Standard)
Shipping label generated
Packing in progress
Shipment 2
In Progress
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Itaque laboriosam, libero molestias nulla.
Carrier: Royal Mail (Standard)
Shipping label generating

TIP

The tracker is display-only. It renders what you declare and nothing more, so ordering, states and content come from your data.

INFO

Every line is drawn as a single SVG overlay, measured from the markers that are actually rendered. Nothing is masked against a background color, so the tracker keeps working on any surface.

INFO

The tracker exposes the ARIA list role and its rows are listitems.

Slots

default
The rows of the tracker; entries and labels.

Examples

Live

Steps complete one by one, the entry flips to delivered and a closing row joins the rail. The lines follow along, since they are measured from what is rendered.

Completed
Order placed
Mar 8, 2026 · 09:12 am
In-progress
Shipment 1
In Progress
Shipping label generated
Packing in progress
Handed to carrier
Out for delivery

<template>
    <FluxFlex
        direction="vertical"
        :gap="18"
        style="width: 100%; max-width: 450px">
        <FluxStatisticsTracker>
            <FluxStatisticsTrackerLabel
                color="success"
                label="Completed"/>

            <FluxStatisticsTrackerEntry
                color="success"
                icon="circle-check"
                title="Order placed"
                when="Mar 8, 2026 · 09:12 am"/>

            <FluxStatisticsTrackerLabel
                :color="isDelivered ? 'success' : 'primary'"
                :label="isDelivered ? 'Completed' : 'In-progress'"/>

            <FluxStatisticsTrackerEntry
                icon="truck"
                title="Shipment 1"
                :color="isDelivered ? 'success' : 'primary'">
                <template #end>
                    <FluxBadge
                        colored
                        :color="isDelivered ? 'success' : 'primary'"
                        :label="isDelivered ? 'Delivered' : 'In Progress'"/>
                </template>

                <FluxStatisticsTrackerSteps>
                    <FluxStatisticsTrackerStep
                        v-for="(step, index) of STEPS"
                        :key="step"
                        :label="step"
                        :state="stateOf(index)"/>
                </FluxStatisticsTrackerSteps>
            </FluxStatisticsTrackerEntry>

            <FluxStatisticsTrackerEntry
                v-if="isDelivered"
                icon="house"
                title="Delivery"
                description="Handed to the customer"/>
        </FluxStatisticsTracker>

        <FluxSecondaryButton
            icon-leading="play"
            :label="running ? 'Running' : 'Run again'"
            :is-loading="running"
            :disabled="running"
            @click="run"/>
    </FluxFlex>
</template>

<script
    setup
    lang="ts">
    import { FluxBadge, FluxFlex, FluxSecondaryButton } from '@flux-ui/components';
    import { FluxStatisticsTracker, FluxStatisticsTrackerEntry, FluxStatisticsTrackerLabel, FluxStatisticsTrackerStep, FluxStatisticsTrackerSteps } from '@flux-ui/statistics';
    import { computed, onBeforeUnmount, onMounted, ref } from 'vue';

    // One step completes per interval; the entry itself flips to delivered once
    // the last one is done, which also adds the closing row to the rail.
    const STEPS = ['Shipping label generated', 'Packing in progress', 'Handed to carrier', 'Out for delivery'];
    const STEP_DURATION = 900;

    const elapsed = ref(0);
    const running = ref(false);

    const isDelivered = computed(() => elapsed.value >= STEPS.length);

    let frame = 0;

    onMounted(() => run());

    onBeforeUnmount(() => cancelAnimationFrame(frame));

    function stateOf(index: number): 'active' | 'done' | 'pending' {
        if (elapsed.value >= index + 1) {
            return 'done';
        }

        return elapsed.value > index ? 'active' : 'pending';
    }

    function run(): void {
        cancelAnimationFrame(frame);
        running.value = true;
        elapsed.value = 0;

        const start = performance.now();

        const tick = (now: number) => {
            elapsed.value = Math.min((now - start) / STEP_DURATION, STEPS.length);

            if (elapsed.value < STEPS.length) {
                frame = requestAnimationFrame(tick);
            } else {
                running.value = false;
            }
        };

        frame = requestAnimationFrame(tick);
    }
</script>

Order tracking

A Tracker card summarizing the progress, followed by a tracker detailing every shipment.

Your Order is on the Way2 shipments · Arriving tomorrow
Completed
Order placed
Mar 8, 2026 · 09:12 am
In-progress
Shipment 1
In Progress
Shipping label generated
Packing in progress
Handed to carrier
Up next
DeliveryTomorrow between 10:00 and 14:00

<template>
    <FluxFlex
        direction="vertical"
        :gap="21"
        style="width: 100%; max-width: 450px">
        <FluxStatisticsTrackerCard
            title="Your Order is on the Way"
            subtitle="2 shipments · Arriving tomorrow"
            icon="truck">
            <FluxStatisticsTrackerCardSegment state="done"/>
            <FluxStatisticsTrackerCardSegment state="done"/>
            <FluxStatisticsTrackerCardSegment state="done"/>
            <FluxStatisticsTrackerCardSegment state="active"/>
            <FluxStatisticsTrackerCardSegment/>
        </FluxStatisticsTrackerCard>

        <FluxStatisticsTracker>
            <FluxStatisticsTrackerLabel label="Completed"/>

            <FluxStatisticsTrackerEntry
                color="success"
                icon="box"
                title="Order placed"
                when="Mar 8, 2026 · 09:12 am"/>

            <FluxStatisticsTrackerLabel label="In-progress"/>

            <FluxStatisticsTrackerEntry
                color="primary"
                icon="truck"
                title="Shipment 1">
                <template #end>
                    <FluxBadge
                        colored
                        color="primary"
                        label="In Progress"/>
                </template>

                <FluxStatisticsTrackerSteps>
                    <FluxStatisticsTrackerStep
                        state="done"
                        label="Shipping label generated"/>

                    <FluxStatisticsTrackerStep
                        state="active"
                        label="Packing in progress"/>

                    <FluxStatisticsTrackerStep label="Handed to carrier"/>
                </FluxStatisticsTrackerSteps>
            </FluxStatisticsTrackerEntry>

            <FluxStatisticsTrackerLabel label="Up next"/>

            <FluxStatisticsTrackerEntry
                icon="house"
                title="Delivery"
                description="Tomorrow between 10:00 and 14:00"/>
        </FluxStatisticsTracker>
    </FluxFlex>
</template>

<script
    setup
    lang="ts">
    import { FluxBadge, FluxFlex } from '@flux-ui/components';
    import { FluxStatisticsTracker, FluxStatisticsTrackerCard, FluxStatisticsTrackerCardSegment, FluxStatisticsTrackerEntry, FluxStatisticsTrackerLabel, FluxStatisticsTrackerStep, FluxStatisticsTrackerSteps } from '@flux-ui/statistics';
</script>

Used components