This documentation is still work in progress, so be please patient.
Docs
Packages
table-client
Table

Table

Common Table is a dummy thing without any data bindings with improved typings and usage, then the pure one from Mantine.

Minimal example

Recommanded bare minimum for a table is to define it's column type and item (entity) it's working with. Also you have to specify column names a table is needing as they force you to specify all of them in the implementation and allows for type-safe competition around the table.

Code

DefaultTable.tsx
import {
    type ITableColumn,
    Table
} from "@leight/table-client";
 
/**
 * Defined your column type
 */
export type IDefaultTableColumn = ITableColumn<{
    /**
     * Each column must provide an ID
     */
    id: string;
    foo: string;
    number: number;
}>;
 
/**
 * Define columns you're working with; table will enforce you to specify all
 * columns by it's typings.
 *
 * That's because you can change or override columns if you wish.
 */
export type IDefaultTableColumnKeys =
    "id"
    | "foo"
    | "number"
 
export const DefaultTable = () => {
    return <Table<IDefaultTableColumn, IDefaultTableColumnKeys>
        columns={{
            /**
             * See type in the IDE to reveal it's mysteries
             */
            id: {
                render: "id",
            },
            /**
             * When you want to render the same value as it's input object,
             * just provide the property name (typed).
             *
             * This structure is enforced, because if you change your mind later
             * on and put some other properties (like width), it's much simpler to
             * do so.
             */
            number: {
                width:  10,
                render: "number",
            },
            foo:    {
                width: 120,
                /**
                 * Yaay! You can provide custom render method. Input is your `TItem`.
                 */
                render: ({foo}) => {
                    return <>extended {foo}</>;
                },
            },
        }}
        /**
         * Items you wish to render; this is the simplest example
         */
        items={[
            {id: "1", foo: "foo1", number: 1},
            {id: "2", foo: "foo2", number: 2},
            {id: "42", foo: "foo42", number: 42},
        ]}
    />;
};

Result

id
number
foo
11extended foo1
22extended foo2
4242extended foo42

A bit advanced example

This example shows how you can change column order and override "built-in" columns provided by table. This is useful when you define default table implementation and later you want to change something without messing up with the original table internals.

Code

BetterTable
import {
    type ITableColumn,
    type ITableProps,
    Table
}                from "@leight/table-client";
import {type FC} from "react";
 
/**
 * Defined your column type
 */
export type IBetterTableColumn = ITableColumn<{
    /**
     * Each column must provide an ID
     */
    id: string;
    foo: string;
    number: number;
}>;
 
/**
 * Define columns you're working with; table will enforce you to specify all
 * columns by its typings.
 *
 * That's because you can change or override columns if you wish.
 */
export type IBetterTableColumnKeys =
    "id"
    | "foo"
    | "number"
 
/**
 * Re-export table props.
 */
export interface IBetterTableProps extends ITableProps<IBetterTableColumn, IBetterTableColumnKeys> {
}
 
export const BetterTable: FC<IBetterTableProps> = props => {
    return <Table<IBetterTableColumn, IBetterTableColumnKeys>
        columns={{
            /**
             * See type in the IDE to reveal its mysteries
             */
            id: {
                /**
                 * When you provide title, it goes through the translation, but
                 * if not found, just the title is returned (in this cas column name
                 * will be just ID)
                 *
                 * The Drawback is that you won't see the whole i18n sentence you have to add
                 * to translations.
                 */
                title:  "ID",
                render: "id",
            },
            /**
             * When you want to render the same value as it's input object,
             * just provide the property name (typed).
             *
             * This structure is enforced, because if you change your mind later
             * on and put some other properties (like width), it's much simpler to
             * do so.
             */
            number: {
                width:  10,
                render: () => "nope",
            },
            foo:    {
                width: 120,
                /**
                 * Yaay! You can provide custom render method. Input is your `TItem`.
                 */
                render: ({foo}) => {
                    return <>extended {foo}</>;
                },
            },
        }}
        order={[
            "number",
            "id",
            "foo"
        ]}
        overrideColumns={{
            number: {
                render: ({number}) => number * 2,
            },
        }}
        /**
         * Items you wish to render; this is the simplest example
         */
        items={[
            {id: "1", foo: "foo1", number: 1},
            {id: "2", foo: "foo2", number: 2},
            {id: "42", foo: "foo42", number: 42},
        ]}
        {...props}
    />;
};

Result

ℹ️

Notice that the first column has different values as the override is in action.

number
ID
foo
21extended foo1
42extended foo2
8442extended foo42

Loading state

Code

Same as above, but with isLoading prop.

Result

number
ID
foo
21extended foo1
42extended foo2
8442extended foo42