Skip to content

Tracker card

The tracker card summarizes a process in a single glance: what it is, where it stands, and how far along it is. The progress itself is declared as a row of Segments, one per step.

Your Order is on the Way2 shipments · Arriving tomorrow

TIP

The card pairs well with a Tracker below it: the card gives the summary, the tracker gives the detail.

Props

title: string
The title of the card.

subtitle?: string
A secondary line shown under the title.

icon?: FluxIconName
An icon shown in a tinted box on the right of the header.

color?: FluxColor
The tint of the header icon.
Default: primary

labels?: top | bottom
Where the labels of the segments are rendered.
Default: bottom

Slots

start
Shown before the title, for example a FluxAvatar or a logo.

end
Shown on the right of the header. Holds the boxed icon of the `icon` prop unless you fill it yourself.

default
The segments of the card.

Examples

Live

The running segment fills up before it hands over to the next one, so the card reads as a process instead of a score.

Your Order is on the WayStep 1 of 5 · Ordered
Ordered
Packed
Shipped
Out for delivery
Delivered

<template>
    <FluxFlex
        direction="vertical"
        :gap="18"
        style="width: 100%; max-width: 450px">
        <FluxStatisticsTrackerCard
            title="Your Order is on the Way"
            :subtitle="subtitle"
            icon="truck">
            <FluxStatisticsTrackerCardSegment
                v-for="(step, index) of STEPS"
                :key="step"
                :label="step"
                :state="stateOf(index)"
                :min="0"
                :max="1"
                :value="valueOf(index)"/>
        </FluxStatisticsTrackerCard>

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

<script
    setup
    lang="ts">
    import { FluxFlex, FluxSecondaryButton } from '@flux-ui/components';
    import { FluxStatisticsTrackerCard, FluxStatisticsTrackerCardSegment } from '@flux-ui/statistics';
    import { computed, onBeforeUnmount, onMounted, ref } from 'vue';

    // Every step takes the same amount of time, so elapsed doubles as the index
    // of the running step and as the progress within it.
    const STEPS = ['Ordered', 'Packed', 'Shipped', 'Out for delivery', 'Delivered'];
    const STEP_DURATION = 900;

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

    const subtitle = computed(() => {
        const index = Math.min(Math.floor(elapsed.value), STEPS.length - 1);

        return elapsed.value >= STEPS.length
            ? 'Delivered · Thank you for your order'
            : `Step ${index + 1} of ${STEPS.length} · ${STEPS[index]}`;
    });

    let frame = 0;

    onMounted(() => run());

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

    function clamp(value: number): number {
        return Math.min(Math.max(value, 0), 1);
    }

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

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

    function valueOf(index: number): number {
        return clamp(elapsed.value - index);
    }

    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>

Labels

Segments can carry a label. Set labels to top to render them above the bar instead of below it.

Onboarding3 of 5 steps completed
Account
Profile
Team
Billing
Done
Onboarding3 of 5 steps completed
Account
Profile
Team
Billing
Done

<template>
    <FluxFlex
        direction="vertical"
        :gap="18"
        style="width: 100%; max-width: 450px">
        <FluxStatisticsTrackerCard
            title="Onboarding"
            subtitle="3 of 5 steps completed"
            icon="user-plus"
            labels="bottom">
            <FluxStatisticsTrackerCardSegment
                label="Account"
                state="done"/>

            <FluxStatisticsTrackerCardSegment
                label="Profile"
                state="done"/>

            <FluxStatisticsTrackerCardSegment
                label="Team"
                state="done"/>

            <FluxStatisticsTrackerCardSegment
                label="Billing"
                state="active"/>

            <FluxStatisticsTrackerCardSegment label="Done"/>
        </FluxStatisticsTrackerCard>

        <FluxStatisticsTrackerCard
            title="Onboarding"
            subtitle="3 of 5 steps completed"
            icon="user-plus"
            labels="top">
            <FluxStatisticsTrackerCardSegment
                label="Account"
                state="done"/>

            <FluxStatisticsTrackerCardSegment
                label="Profile"
                state="done"/>

            <FluxStatisticsTrackerCardSegment
                label="Team"
                state="done"/>

            <FluxStatisticsTrackerCardSegment
                label="Billing"
                state="active"/>

            <FluxStatisticsTrackerCardSegment label="Done"/>
        </FluxStatisticsTrackerCard>
    </FluxFlex>
</template>

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

Colors

The header icon and the segments are tinted separately, so a card can follow the color of the process it tracks.

DeploymentProduction · Build 482
Storage upgradeWaiting for approval

<template>
    <FluxFlex
        direction="vertical"
        :gap="18"
        style="width: 100%; max-width: 450px">
        <FluxStatisticsTrackerCard
            color="success"
            title="Deployment"
            subtitle="Production · Build 482"
            icon="rocket">
            <FluxStatisticsTrackerCardSegment
                color="success"
                state="done"/>

            <FluxStatisticsTrackerCardSegment
                color="success"
                state="done"/>

            <FluxStatisticsTrackerCardSegment
                color="success"
                state="done"/>

            <FluxStatisticsTrackerCardSegment
                color="success"
                state="done"/>
        </FluxStatisticsTrackerCard>

        <FluxStatisticsTrackerCard
            color="warning"
            title="Storage upgrade"
            subtitle="Waiting for approval"
            icon="database">
            <FluxStatisticsTrackerCardSegment
                color="warning"
                state="done"/>

            <FluxStatisticsTrackerCardSegment
                color="warning"
                state="active"/>

            <FluxStatisticsTrackerCardSegment/>
            <FluxStatisticsTrackerCardSegment/>
        </FluxStatisticsTrackerCard>
    </FluxFlex>
</template>

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

Used components