Skip to content

Data table

Data tables are a powerful tool for organizing and presenting large sets of data in a structured and easy-to-read format. Like traditional tables, data tables use rows and columns to organize data, but they also offer additional functionality and features that are specifically designed for working with large datasets.

One of the key benefits of using data tables is their ability to handle large amounts of data, making them an ideal choice for applications that require data visualization and analysis. Data tables often include advanced sorting and filtering capabilities, allowing users to quickly search and analyze data based on specific criteria.

Person
Status
Desiree KulasRosalyn_Gerlach@hotmail.com
Active
Mr. Wallace SchulistAnnalise44@yahoo.com
Active
Jessica BuckridgeGeovanny15@hotmail.com
Inactive
Tommy HellerJayden_Trantow35@yahoo.com
Inactive
Dr. Reilly VonRuedenRico.Kuhic83@gmail.com
Inactive

Required icons

arrow-down-a-z
arrow-up-a-z
arrow-up-arrow-down
check
circle-xmark
minus

Props

items: T[]
The data to show in the table. This should already be the current page's data — pagination is handled server-side. Pass the subset of items for the active page here.

fill-columns?: number
The number of columns to render placeholder cells for when the page has fewer items than `per-page`.

is-bordered?: boolean
Show borders between cells.

is-hoverable?: boolean
Enable a hover state for each row.

is-loading?: boolean
Show that the data table is loading.

is-separated?: boolean
Show borders between rows.

is-striped?: boolean
Show alternating backgrounds for each row.

limits: number[]
The available options for the pagination limit.

page: number
The currently active page, starting from 1. Used for slot bindings and the pagination bar display only — it does not slice the items array.

per-page: number
The number of rows to show per page.

selection-mode?: 'single' | 'multiple'
Enables row selection. Use `single` for at most one selected row, or `multiple` for an array of selected rows. Requires `unique-key` to be set.

total: number
The total number of items in the data set.

unique-key?: string
The unique key for each row.

Emits

limit: [number]
Triggered when the per-page limit is changed by the user.

navigate: [number]
Triggered when the user navigates to a different page.

update:selected: [string | number | null | (string | number)[]]
Triggered when the selection changes. The payload type matches `selection-mode` — a single id (or `null`) for `single`, an array of ids for `multiple`.

Slots

colgroups
A slot to render `<colgroup>` elements that control column sizing.

filter ({
    readonly page: number;
    readonly per-page: number;
    readonly items: T[];
    readonly total: number;
})

Renders above the table header — typically a `FluxFilterBar` for filtering the data set.

footer ({
    readonly page: number;
    readonly per-page: number;
    readonly items: T[];
    readonly total: number;
})

The footer of the data table.

header ({
    readonly page: number;
    readonly per-page: number;
    readonly items: T[];
    readonly total: number;
})

The header of the data table.

pagination ({
    readonly page: number;
    readonly per-page: number;
    readonly items: T[];
    readonly total: number;
})

Replaces the default pagination bar — useful when you want to render a custom paginator.

[key: string] ({
    readonly index: number;
    readonly page: number;
    readonly per-page: number;
    readonly item: T;
    readonly items: T[];
    readonly total: number;
    readonly is-selected: boolean;
})

A slot representing a cell for each visible row.

Server-side pagination

The data table does not paginate items internally. The items prop should contain only the rows for the currently active page, fetched from your server or API. The page and per-page props are used to drive the pagination bar and are exposed through slot bindings so you can display them, but the component never slices or filters the items array itself.

Examples

File manager

A data table that is used for file management.

Name
Owner
that_aw.pngimage/png
Beau Hegmann
submitter.pngimage/png
Dr. Melvin Fadel-Price
yowza_squiggly_across.pngimage/png
Jasen Kirlin IV
expensive_fray.pngimage/png
Derrick Bogan
excluding.pngimage/png
Payton Breitenberg IV

<template>
    <FluxPane>
        <FluxDataTable
            :items="dataSet"
            :limits="[]"
            :page="1"
            :per-page="20"
            :total="dataSet.length"
            is-hoverable>
            <template #header>
                <FluxTableHeader>Name</FluxTableHeader>
                <FluxTableHeader>Owner</FluxTableHeader>
                <FluxTableHeader is-shrinking/>
            </template>

            <template #name="{item: {name, type}}">
                <FluxTableCell>
                    <FluxFlex :gap="21">
                        <FluxBoxedIcon name="image"/>

                        <FluxFlex direction="vertical">
                            <strong>{{ name }}</strong>
                            <small>{{ type }}</small>
                        </FluxFlex>
                    </FluxFlex>
                </FluxTableCell>
            </template>

            <template #owner="{item: {owner}}">
                <FluxTableCell>{{ owner }}</FluxTableCell>
            </template>

            <template #actions="{}">
                <FluxTableCell>
                    <FluxTableActions>
                        <FluxAction icon="arrow-down-to-line"/>
                        <FluxAction icon="ellipsis-h"/>
                    </FluxTableActions>
                </FluxTableCell>
            </template>
        </FluxDataTable>
    </FluxPane>
</template>

<script
    lang="ts"
    setup>
    import { FluxAction, FluxBoxedIcon, FluxDataTable, FluxFlex, FluxPane, FluxTableActions, FluxTableCell, FluxTableHeader } from '@flux-ui/components';
    import { faker } from '@faker-js/faker';
    import { computed } from 'vue';

    const dataSet = computed(() => Array(5)
        .fill(null)
        .map((_, index) => ({
            id: index,
            name: faker.system.commonFileName('png'),
            owner: faker.person.fullName(),
            type: 'image/png'
        })));
</script>

Paginated

A data table that is split into pages.

Name
Item 1
Item 2
Item 3
Item 4
Item 5
Item 6
Item 7
Item 8
Item 9
Item 10
1–10 of 500

<template>
    <FluxPane>
        <FluxDataTable
            :items="visibleItems"
            is-hoverable
            :limits="[5, 10, 25, 50, 100]"
            :page="page"
            :per-page="perPage"
            :total="dataSet.length"
            @limit="limit => perPage = limit"
            @navigate="p => page = p">
            <template #header>
                <FluxTableHeader>Name</FluxTableHeader>
            </template>

            <template #name="{item: {name}}">
                <FluxTableCell>{{ name }}</FluxTableCell>
            </template>
        </FluxDataTable>
    </FluxPane>
</template>

<script
    lang="ts"
    setup>
    import { FluxDataTable, FluxPane, FluxTableCell, FluxTableHeader } from '@flux-ui/components';
    import { computed, ref, unref } from 'vue';

    const page = ref(1);
    const perPage = ref(10);

    const dataSet = computed(() => Array(500)
        .fill(null)
        .map((_, index) => ({
            id: index,
            name: `Item ${index + 1}`
        })));

    const visibleItems = computed(() => unref(dataSet).slice((unref(page) - 1) * unref(perPage), unref(page) * unref(perPage)) ?? []);
</script>

Selectable rows

A data table where multiple rows can be selected via checkboxes.

MembersNo rows selected
Person
Status
Miss Marie TowneGretchen_Volkman@hotmail.com
Active
Dora PaucekDoyle_Pouros@gmail.com
Active
Murphy YostKrystal.Bins@hotmail.com
Inactive
Dr. Thad BoscoArielle29@hotmail.com
Active
Chesley RennerSandy12@gmail.com
Inactive

<template>
    <FluxPane>
        <FluxPaneHeader
            title="Members"
            :subtitle="selected.length === 0 ? 'No rows selected' : `${selected.length} row${selected.length === 1 ? '' : 's'} selected`"/>

        <FluxDataTable
            v-model:selected="selected"
            :items="dataSet"
            :limits="[]"
            :page="1"
            :per-page="5"
            selection-mode="multiple"
            :total="dataSet.length"
            unique-key="id"
            is-hoverable>
            <template #header>
                <FluxTableHeader>
                    Person
                </FluxTableHeader>

                <FluxTableHeader is-shrinking>
                    Status
                </FluxTableHeader>
            </template>

            <template #name="{item: {name, email}}">
                <FluxTableCell content-direction="column">
                    <strong>{{ name }}</strong>
                    <small>{{ email }}</small>
                </FluxTableCell>
            </template>

            <template #isActive="{item: {isActive}}">
                <FluxTableCell>
                    <FluxBadgeStack>
                        <FluxBadge
                            v-if="isActive"
                            color="success"
                            icon="circle-check"
                            label="Active"/>

                        <FluxBadge
                            v-else
                            color="danger"
                            icon="circle-xmark"
                            label="Inactive"/>
                    </FluxBadgeStack>
                </FluxTableCell>
            </template>
        </FluxDataTable>
    </FluxPane>
</template>

<script
    lang="ts"
    setup>
    import { FluxBadge, FluxBadgeStack, FluxDataTable, FluxPane, FluxPaneHeader, FluxTableCell, FluxTableHeader } from '@flux-ui/components';
    import { faker } from '@faker-js/faker';
    import { computed, ref } from 'vue';

    const selected = ref<number[]>([]);

    const dataSet = computed(() => Array(5)
        .fill(null)
        .map((_, index) => ({
            id: index,
            name: faker.person.fullName(),
            email: faker.internet.email(),
            isActive: faker.datatype.boolean()
        })));
</script>

Used components