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 ​