TinyBase logoTinyBase β

<TableInHtmlTable />

In this demo, we showcase the TableInHtmlTable component.

Rather than building the whole demo and boilerplate from scratch, we're making changes to the <ValuesInHtmlTable /> demo to support this new component.

Set Up

We switch out the ValuesInHtmlTable component and import the TableInHtmlTable component instead.

-const {ValuesInHtmlTable} = TinyBaseUiReactDom;
+const {TableInHtmlTable} = TinyBaseUiReactDom;

This component renders Table content rather than Values, so we change the load sequence to asynchronously load some tabular data, stealing from the Movie Database demo.

-  useMemo(() => {
-    loadValues(store);
+  useMemo(async () => {
+    await loadTable(store, 'genres');
     setIsLoading(false);
   }, []);

Loading Data

We're loading a table of data in exactly the same way as we did in the Movie Database demo:

const NUMERIC = /^[\d\.]+$/;

const loadTable = async (store, tableId) => {
  store.startTransaction();
  const rows = (
    await (await fetch(`https://tinybase.org/assets/${tableId}.tsv`)).text()
  ).split('\n');
  const cellIds = rows.shift().split('\t');
  rows.forEach((row) => {
    const cells = row.split('\t');
    if (cells.length == cellIds.length) {
      const rowId = cells.shift();
      cells.forEach((cell, c) => {
        if (cell != '') {
          if (NUMERIC.test(cell)) {
            cell = parseFloat(cell);
          }
          store.setCell(tableId, rowId, cellIds[c + 1], cell);
        }
      });
    }
  });
  store.finishTransaction();
};

This is a small and narrow Table, with just Id and name for the sixteen movie genres.

Using the TableInHtmlTable Component

The TableInHtmlTable component is almost as simple as the ValuesInHtmlTable component, though it will need one prop, the Table Id:

 const Body = () => {
   return (
     <>-      <ValuesInHtmlTable />
-
-      <ValuesInHtmlTable headerRow={false} idColumn={false} />
+      <TableInHtmlTable tableId='genres' />
+      <TableInHtmlTable tableId='genres' headerRow={false} idColumn={false} />
     </>
   );
 };

Again, that's it.

As before, you can see that you can disable the top header row and Id column on the left with the headerRow and idColumn props respectively.

Customizing Cells

This is a good opportunity to demonstrate how the table components can take custom components for rendering the inside of the cells in the table. Let's create a third table, where we pass in a custom component called DictionaryCell.

That component should accept props for the Table, Row, and Cell Ids (as well as the Store) in order to create a different rendering. Here we create a link to an online dictionary for each word in the column:

const DictionaryCell = ({tableId, rowId, cellId, store}) => {
  const word = useCell(tableId, rowId, cellId, store);
  return (
    <a
      href={'https://www.merriam-webster.com/dictionary/' + word}
      target="_blank"
    >
      {word}
    </a>
  );
};

Also we need to update the imports to get access to the useCell hook:

-const {Provider, useCreateStore} = TinyBaseUiReact;
+const {Provider, useCell, useCreateStore} = TinyBaseUiReact;

Then we configure this component to be used for the name Cell in the table, and capitalize the name at the top of the column:

const customCells = {name: {label: 'Name', component: DictionaryCell}};

And apply that configuration to the table via the customCells prop:

       <TableInHtmlTable tableId='genres' headerRow={false} idColumn={false} />
+      <TableInHtmlTable tableId='genres' customCells={customCells} />
     </>

Finally, we can give the links some default styling.

a {
  color: inherit;
}

Take a look at the TableInHtmlTableProps type and HtmlTableProps type to see all the ways in which you can configure this component, and again, click the 'CodePen' link under the demo above to try them out.

Let's move on to a slightly more complex component in the <SortedTableInHtmlTable /> demo.