Table

Table

The Table is the main way to present data in Bubbles. Tables are created with individual components, meaning you'll import TableRow and TableCell.

The Table is made up of an optional TableHeader, where you can set the headings for rows. And TableRow, which itself is just an array of TableCell components.

If you're looking to add filters or pagination at the bottom of your table, you'll want to slot the Table into a Card, and add the CardHeader with filters and CardFooter with pagination.




Props


padding string roomy
"roomy" or "compact". Decides how much spacing is between each row.


id string
You can pass in an ID to the component if you need to reference it later. If you do not pass an ID, there will be a unique id added to the component.


overflow boolean false
Allow for the table contents to overflow the container. The table will become scrollable.

TableHeader

This is the top of the Table that explains what each of the column are.




Props


cells array<Object>
Cells are an array of Objects that will add text to the top of the table. The number of cells should match the numbers for TableCell components that are in each TableRow.


cell[].label string
This is the text the user will see. Leave this blank or pass in null to add a blank cell. Useful if you have an icon or image in one of your TableCell and don't want a header.


cell[].align string
Normally cells are aligned to the left, but if you want to align the header to the right, pass in "right" or "end


cell[].width integer
Set the width to 0 to hide this item


cell[].mobile_width integer
Set to zero to hide this cell on mobile devices



"Select All" Checkbox Props

In some tables, you'll want the user to select multiple items and do an action, like deleting all items. Each TableRow can have a checkbox component. Adding an option to the header will let you select and deselect all checkboxes in the same column, and adjust to UI of the CardHeader to display options.



cell[].checkbox boolean
Set this value to true to display the checkbox in the header


cell[].options array<Object>
An array that will contain the options the user can select. These options should be functions that apply to all selected items. To get all of the selected rows, make sure you have provided an id property to all rows, then import the getSelectedTableRows.

Show Details
option[].label string
The text the user sees for the option
option[].value string
The value that will be added for the url query param
option[].caption string
More details to give about the option
option[].img string
An image that will be displayed on the left of the text
option[].icon string
An icon to display on the right. Defaults to an arrow. You can remove this by setting this value to null
option[].onselect function
A function that can be run if this option is selected




Table Sorting

At some point you'll want to sort the data in your table. There are two ways you can sort the data. First, you can sort the data in place, that means you are not refetching data from an API and the other route is to fetch the data from the API and have the server do the sorting. The sorting props let you do both. Refetching data will add query parameters to the url, which will trigger the load function to run. Make sure that you have destructured the url property in the load function.



cell[].sort Object
Set this value to sort the table rows for the end user. The result is when the user clicks on the cell to sort, an event gets fired. If you are modifying the query params and refetching data, you don't need to do anything at this point. If you are sorting locally, you'll need to listen for the sort event dispatched to the header, and sort the data yourself. Bubbles has a built in utility function that can sort for you.

Show Details
cell.sort.id string
The prop name you want to search for. If the prop is nested, use dot notation like "hello.world"
cell.sort.order string
The default order for the displayed arrow. Defaults to "ascending" but you can change to "descending"
cell.sort.query boolean
Set to true if you want the sort to add query params to refetch the API
cell.sort.key string
The key for the query param. Will default to the ID
cell.sort.value string
The value for the query param, will default to the order

import { TableHeader, sort } from "bubbles-ui";

$: data = [] //This is the data for your table

<TableHeader
  on:sort={(event) => (data = sort(data, event.detail.sort_by, event.detail.order))} //Will sort the data locally without refetching
  cells={[
    { label: "Name", sort: { id: "name", query: true, key: "name" } }, //Will add a query param, with custom key
    { label: "Weight", sort: { id: "size.weight" } }, //The sort function will sort by numbers and find the value nested on obj.size.weight
  ]}
/>;

TableRow




Props


id string
You can set an ID for the row to reference it later. For example, set the id of the TableRow to each user you're displaying in your table so you can go to that user's details page if the table is clicked on.


href string
The href value for the entire row. This is useful is you are using a Table for a settings menu, where you don't care where the user clicks. If you have a more complex cell, set the href on the cell, not the row.


onclick function
You can run a function when the user clicks on the row. If you just want to take the user to a new page, use href because it will have better performance as the page with be prefetched.


wrap boolean true
Set to false if you don't want to wrap the contents of each cell.


mobile_wrap boolean true
Set to false fi you don't wan to wrap the contents of each cell mobile only

TableCell

The cell that is inside of the TableRow.

When a user is viewing your table on a mobile device, we'll need the table to be responsive. You can attempt to make the whole table row overflow but that is a bad user experience. Ideally, on a smaller screen, you'll want to present less information on your table, and let the user navigate to a page with more details.

There are specific mobile properties on for the TableCell to help you deal with small screen devices.

There are some predefined props for the table for standard layouts. You can of course just add your own custom markup as a slot.




Props


text string
This will add a string of text to the cell


href string
Will cause the text to be an href. This is different than setting the TableRow as an href, since only this part will be clickable. Best used on complex tables that may have multiple clickable parts.


caption string
This will add a second line of text below in grey below the text


large boolean false
Make the text in the cell large. Best used for simple tables like settings screens


bold boolean false
Will make the text in this cell bold. Great for complex table to show the most import piece of information.


align string left
By default the text in the cell is left aligned, but you can change that to "right"


img.src string
If you pass in an img, Bubbles will assume you want to add an image to the cell, like someone's profile picture. The image will be added and all text properties will be ignored.


img.alt string
If you pass an image, add an alt tag for accessibility.


tag object
ou can add a tag into your cell. See the tag sectionfor more details.


button object
If you add a button property, Bubbles will assume you want to add an IconButton to that cell. See the props needed for an IconButton here


width number|string
The the width for the cell. Enter a number for the width to be treated as a percentage, or a string with the units you want like "3rem" or "20px"


mobile_width number
Select the width this cell will take up on small screens. If you want to hide the cell on mobile, set the value to 0.


mobile_order number
This is the order css property. You can change the order or elements by passing in larger integers and move them left in the stack by passing in larger negative integers.


wrap boolean true
Set to false if you don't want to wrap the contents of the cell.


mobile_wrap boolean true
Set to false fi you don't wan to wrap the contents of mobile only

<script>
  import { Table, TableRow, TableCell, pageStore } from "bubbles-ui";
</script>

<Table>
  <TableRow href="#table">
    <TableCell text="Profile" large={true} bold={true} caption="Edit your profile and update your photo" />
    <TableCell button={{ icon: "arrowRight" }} />
  </TableRow>
  <TableRow href="#table">
    <TableCell text="Notifications" large={true} caption="Select how and went we message you" />
    <TableCell button={{ icon: "arrowRight" }} />
  </TableRow>
  <TableRow href="#table">
    <TableCell text="Billing" large={true} bold={true} caption="Edit your payment methods and see past transactions" />
    <TableCell button={{ icon: "arrowRight" }} />
  </TableRow>
</Table>
<script>
  import {
    Card,
    CardHeader,
    CardFooter,
    Row,
    Column as Column100,
    Table,
    TableHeader,
    TableRow,
    TableCell,
    Pagination,
    sort,
  } from "bubbles-ui";

  import store from "$assets/utils/store";
  import { getSelectedTableRows, deselectTableRows } from "$lib/utils/table";

  $: pagination = $store?.pagination ? $store.pagination : {};
  $: pokemon = $store.pokemon ? $store.pokemon : [];

  function typeColor(type) {
    switch (type) {
      case "normal":
        return "gray-light";
      case "fire":
        return "error";
      case "water":
        return "info";
      case "grass":
        return "success";
      case "electric":
        return "warning";
      case "ice":
        return "info-light";
      case "fighting":
        return "error-light";
      case "poison":
        return "primary";
      case "ground":
        return "warning-light";
      case "flying":
        return "primary-light";
      case "psychic":
        return "secondary-light";
      case "bug":
        return "success-light";
      case "rock":
        return "dark-light";
      case "ghost":
        return "primary-border";
      case "dark":
        return "dark";
      case "dragon":
        return "primary-light";
      case "steel":
        return "gray";
      case "fairy":
        return "secondary";
      default:
        return "gray";
    }
  }
</script>

<Row>
  <Column>
    <Card>
      <CardHeader
        title="Complex Table Example"
        caption="This example uses an external API for data, which may run slowly especially when using the search."
        buttons={[
          { icon: "search", color: "gray-lighter", search: true },
          { icon: "more", color: "gray-lighter" },
        ]}
        border={false}
        filters={[
          {
            id: "type",
            label: "Type",
            value: "",
            options: types.map((type) => {
              if (type === "break") {
                return "break";
              }

              return {
                label: type,
                value: type === "All" ? "" : type.toLowerCase(),
              };
            }),
          },
        ]}
      />
      <Table id="pokemon-table" padding="roomy">
        <TableHeader
          on:sort={(event) => (pokemon = sort(pokemon, event.detail.sort_by, event.detail.order))}
          cells={[
            {
              checkbox: true,
              options: [
                {
                  label: "Print Selected Rows To Console",
                  value: "label1",
                  onselect: (event) => {
                    console.log(getSelectedTableRows("pokemon-table"));
                    deselectTableRows("pokemon-table");
                  },
                },
              ],
            },
            { label: null },
            { label: "Name", sort: { id: "name" } },
            { label: "Weight", sort: { id: "weight" } },
            { label: "Type(s)" },
            { label: "Possible Moves", align: "end" },
            { label: null, align: "end" },
          ]}
        />
        {#each pokemon as poke}
          <TableRow id={poke.id}>
            <TableCell checkbox={{ value: false }} />
            <TableCell img={{ src: poke?.sprites?.front_default, alt: "Sprite" }} mobile_width={10} />
            <TableCell
              text={poke.name}
              href={`/examples/pokedex/${poke.name}`}
              caption={`Pokedex Number: ${poke.id}`}
              bold={true}
              mobile_width={70}
            />
            <TableCell text={`${poke.weight} lbs`} mobile_width={0} />
            <TableCell
              mobile_width={0}
              rows={[
                [
                  {
                    tag: {
                      label: poke?.types[0]?.type?.name,
                      color: typeColor(poke?.types[0]?.type?.name),
                      margin: "0 0 .25rem 0",
                    },
                  },
                ],
                [
                  {
                    tag: {
                      label: poke?.types[1]?.type?.name,
                      color: typeColor(poke?.types[1]?.type?.name),
                      margin: "0.25rem 0 0 0",
                    },
                  },
                ],
              ]}
            />

            <TableCell
              tag={{ label: poke.moves.length, color: "primary", min_width: 2.75 }}
              align="right"
              mobile_width={0}
            />

            <TableCell
              mobile_width={10}
              button={{
                icon: "more",
                options: [
                  {
                    label: "Encounters",
                    href: poke.location_area_encounters,
                    caption: "Areas you can find this pokemon",
                  },
                  "break",
                  {
                    label: "View JSON",
                    href: poke.species.url,
                  },
                  {
                    label: "Shiny Sprite",
                    href: poke.sprites.front_shiny,
                  },
                ],
              }}
            />
          </TableRow>
        {/each}
      </Table>
      <CardFooter>
        <Pagination {...pagination} />
      </CardFooter>
    </Card>
  </Column>
</Row>
Complex Table Example

This example uses an external API for data, which may run slowly especially when using the search.

Type
All
Option Indicator Name
Option Indicator Weight
Type(s)
Possible Moves
Sprite
bulbasaur

Pokedex Number: 1

69 lbs

grass
poison
86
Sprite
ivysaur

Pokedex Number: 2

130 lbs

grass
poison
83
Sprite
venusaur

Pokedex Number: 3

1000 lbs

grass
poison
96
Sprite
charmander

Pokedex Number: 4

85 lbs

fire
105
Sprite
charmeleon

Pokedex Number: 5

190 lbs

fire
103
Sprite
charizard

Pokedex Number: 6

905 lbs

fire
flying
131
Sprite
squirtle

Pokedex Number: 7

90 lbs

water
106
Sprite
wartortle

Pokedex Number: 8

225 lbs

water
101
Sprite
blastoise

Pokedex Number: 9

855 lbs

water
120
Sprite
caterpie

Pokedex Number: 10

29 lbs

bug
5