Solid data table

Table, Bro is the Custom Element ‹table-bro›, so a Solid app renders it in JSX as it is. A ref gives the element its columns, rows and config by configure(), on:bro-action listens to its events, and the theme attribute sets its theme. The page below is the working page of the sample project samples/frameworks/solid of the repository, with Solid 1.9; StackBlitz opens it in the browser.

Loading
Items per page:

How do I install Table, Bro in Solid?

  1. Install the packages

    The table engine @table-bro/core and a skin, @table-bro/native of plain HTML elements; @table-bro/bootstrap with bootstrap gives the skin of Bootstrap 5:

    npm install @table-bro/core @table-bro/native
    
  2. Register the element and the skin

    Once, before the tables: the import of the skin defines ‹table-bro› and registers the skin nv. The CSS of the core and of the skin come as imports, which Vite and the other bundlers take. src/skin.ts:

    // The CSS of the core and of the skin, then the skin: its import defines <table-bro> and registers the skin nv
    import '@table-bro/core/dist/table-bro.min.css';
    import '@table-bro/native/dist/table-bro.native.min.css';
    import '@table-bro/native';
    
    import './sample-page.css';
    
  3. Describe the columns, the rows and the config

    conf.skin names the registered skin. src/orders.ts:

    import type {BroCol, BroConfig, BroRow} from '@table-bro/core';
    
    export interface Order extends BroRow {
      description: string;
      price: number;
    }
    
    export const cols: BroCol<Order>[] = [
      {
        title: 'Description',
        name: 'description'
      }, {
        title: 'Price',
        name: 'price',
        dataType: 'number',
        className: 'bro-col_text-right'
      }
    ];
    
    export const rows: Order[] = [
      {
        description: 'Modern Cotton Chair',
        price: 100
      }, {
        description: 'Awesome Concrete Ball',
        price: 200
      }
    ];
    
    export const conf: BroConfig = {
      skin: 'nv',
      toolbarTitle: 'Orders'
    };
    

How do I pass cols, rows and conf?

The columns, the rows and the config go to the table in one call, configure({cols, rows, conf}), once the element is mounted: ref gives the element (Solid, ref), onMount makes the call. on:bro-action adds the listener of the event by its exact name (Solid, on:*); the sample logs the name of each action. src/OrdersTable.tsx:

import {onMount} from 'solid-js';

import type {BroActionDetail, TableBroHTMLElement} from '@table-bro/core';

import {cols, conf, rows} from './orders';

export function OrdersTable() {
  let table!: TableBroHTMLElement;

  onMount(() => table.configure({cols, rows, conf}));

  return (
    <div class="bro-table-shadow-container">
      <table-bro id="orders" ref={table} theme="auto"
                 on:bro-action={(event: CustomEvent<BroActionDetail>) => console.log(event.detail.action)}></table-bro>
    </div>
  );
}

vite-plugin-solid compiles the JSX of Solid, and "jsx": "preserve" with "jsxImportSource": "solid-js" in tsconfig.json gives its types to TypeScript. vite.config.ts:

import {defineConfig, mergeConfig} from 'vite';
import solid                       from 'vite-plugin-solid';

import {samplePage} from './sample-page.config.ts';

export default mergeConfig(samplePage, defineConfig({
  plugins: [
    solid()
  ]
}));

mergeConfig adds sample-page.config.ts of the sample, the source maps and the readable code of its working page; a project of its own exports defineConfig() with the plugins alone.

How does TypeScript know the element?

A declaration adds ‹table-bro› to the JSX of Solid, with the methods of TableBroHTMLElement, and bro-action to its events of on:. src/elements.d.ts:

// The element <table-bro> in the JSX of Solid, with its attribute theme and its event bro-action for on:bro-action
import type {JSX as SolidJSX} from 'solid-js';

import type {BroActionDetail, TableBroHTMLElement} from '@table-bro/core';

declare module 'solid-js' {
  namespace JSX {
    interface IntrinsicElements {
      'table-bro': SolidJSX.HTMLAttributes<TableBroHTMLElement> & {theme?: 'light' | 'dark' | 'auto'};
    }

    interface CustomEvents {
      'bro-action': CustomEvent<BroActionDetail>;
    }
  }
}

How do I render it?

src/main.tsx imports the skin before the tables:

// The skin is registered before the tables
import './skin';

import {render} from 'solid-js/web';

import {OrdersTable} from './OrdersTable';

render(() => <OrdersTable />, document.getElementById('app')!);

How do I switch the theme?

The theme attribute or property of the table is 'light', 'dark' or 'auto', which follows the color scheme of the system; the attribute wins over config.theme. The sample sets 'auto', as a table without the attribute does; a variable of the state bound to it switches the theme, and the table puts the class bro-dark-theme or bro-light-theme on itself. More in Dark/Light mode.

Questions

Does Solid need a wrapper for Custom Elements?

No. Solid passes all 32 tests of Custom Elements Everywhere; on: listens to an event by its exact name, as bro-action. Its package solid-element also turns a Solid component into a Custom Element (Solid, solid-element).

Can I bind cols and rows as props?

The table takes its data by configure(), one call for the columns, the rows and the config. New rows go by replaceRows(rows) on the same ref, as in an effect of a signal of the rows.

Does it work with SolidStart?

The element needs the browser: onMount runs only there, so the server render leaves the element empty and the browser fills it.

Related

Getting started, Custom content in tables using Custom Elements, MCP server for AI coding agents, Angular data table, Preact data table, React data table, Svelte data table, Vue 3 data table.

DJ