Table

A table you can build from data or write out by hand, with stripes, hover rows and border options.

About

Pass headers and data and the Table builds the rows for you, or write THead, TBody, TR, TH and TD out by hand. The two styles mix freely, and the output is always wrapped in a horizontally scrollable container.

Example

There are several ways to build a table. For example:

  • Using data
  • Using snippet
  • Manually using the components

Setup

At first import the relevant components of the table.

Svelte
<script>
  import { Table, THead, TBody, TR, TH, TD } from "theui-svelte";
</script>

Example: Using Props

The Table component allows you to generate tables dynamically using data. This approach is useful when you have structured data and want to render it efficiently without manually defining each row and column. This method ensures your table remains dynamic and adaptable to different datasets.

Pass the headers, data, and keys as props to the Table component.

  • headers: string[] - An array of column headers.
  • data: object[] - An array of objects representing table rows.
  • keys: string[] - An array of keys that map data fields to columns.

Cell values passed this way are rendered as plain text, so HTML inside them is not rendered. A key that is missing from a row renders an empty cell. To add custom markup, use the components as shown in the next example.

Heading 1Heading 2Heading 3Heading 4
Data 11Data 12Data 13Data 14
Data 21Data 22Data 23Data 24
Data 31Data 23Data 33Data 43
Svelte
<script>
  let headers = ["Heading 1", "Heading 2", "Heading 3", "Heading 4"];
  let data = [
    {item1: "Data 11", item2: "Data 12", item3: "Data 13", item4: "Data 14"},
    {item1: "Data 21", item2: "Data 22", item3: "Data 23", item4: "Data 24"},
    {item1: "Data 31", item2: "Data 23", item3: "Data 33", item4: "Data 43"},
  ];
  let keys = ["item1", "item2", "item3", "item4"];
</script>

<!-- Option 1 -->
<Table {headers} {data} {keys} />

<!-- Option 2 -->
<Table>
  <THead {headers} />
  <TBody {data} {keys} />
</Table>

<!-- Option 3 -->
<Table {headers}>
  <TBody>
    {#each data as d}
      <TR data={d} {keys} />
    {/each}
  </TBody>
</Table>

Example: Using Components

Instead of props or dynamically looping through the data, the table content is written manually using the THead, TBody, TR, TH and TD components.

  • <THead> - Contains the header row.
  • <TBody> - Contains the table rows.
  • <TR> - Represents a table row. Add tableHeader={true} to the header row so it gets the trHeadClasses styles. When a TR renders its cells from the data prop, tableHeader also makes it render <th> cells instead of <td>.
  • <TH> - Represents a header cell.
  • <TD> - Represents a table data containing the actual data.
Heading 1Heading 2Heading 3Heading 4
Data 11Data 12Data 13Data 14
Data 21Data 22Data 23Data 24
Data 31Data 23Data 33Data 43
Svelte
<Table>
  <THead>
    <TR tableHeader={true}>
      <TH>Heading 1</TH>
      <TH>Heading 2</TH>
      <TH>Heading 3</TH>
      <TH>Heading 4</TH>
    </TR>
  </THead>
  <TBody>
    <TR>
      <TD>Data 11</TD>
      <TD>Data 12</TD>
      <TD>Data 13</TD>
      <TD>Data 14</TD>
    </TR>
    ...
    ...
  </TBody>
</Table>

Custom Header

If you need custom headers or anything other than text in the header just put your custom items in the TH component. For example:

Sort Sort
Svelte
<Table>
  <THead>
    <TR>
      <TH class="items-center gap-2">
        Sort
        <Svg class="inline">
          <path d="M3.5 12.5a.5.5 0 0 ... 0 1h1a.5.5 0 0 0 0-1z"/>
        </Svg>
      </TH>
      <TH class="items-center gap-2">
        Sort
        <Svg class="inline">
          <path d="M3.5 2.5a.5.5 0 0 0-1 ... 1h1a.5.5 0 0 0 0-1z"/>
        </Svg>
      </TH>
    </TR>
  </THead>
</Table>

Table Border

The border prop controls where borders appear in the table. By default, it is set to "both". Setting it to "x" adds borders only between columns, while "y" applies borders only between rows. The default option, "both", adds borders between both rows and columns, and "none" removes all borders. This prop allows you to customize the table's appearance based on your design preferences.

Horizontal border: border="x"
Heading 1Heading 2Heading 3Heading 4
Data 11Data 12Data 13Data 14
Data 21Data 22Data 23Data 24
Data 31Data 23Data 33Data 43
Vertical border: border="y"
Heading 1Heading 2Heading 3Heading 4
Data 11Data 12Data 13Data 14
Data 21Data 22Data 23Data 24
Data 31Data 23Data 33Data 43
No border: border="none"
Heading 1Heading 2Heading 3Heading 4
Data 11Data 12Data 13Data 14
Data 21Data 22Data 23Data 24
Data 31Data 23Data 33Data 43
Svelte
<Table {headers} {data} {keys} border="x" />
<Table {headers} {data} {keys} border="y" />
<Table {headers} {data} {keys} border="none" />

Table Spacing

The space prop adjusts the cell padding to control the overall table spacing, affecting how compact or spacious the table appears.

  • "compact" - Reduces padding for a denser layout, making the table more space-efficient.
  • "default" (Default value) - Uses the standard padding, providing a balanced look.
  • "comfortable" - Increases padding for a more spacious and readable layout.
Compact spacing: space="compact"
Heading 1Heading 2Heading 3Heading 4
Data 11Data 12Data 13Data 14
Data 21Data 22Data 23Data 24
Data 31Data 23Data 33Data 43
Comfortable spacing: space="comfortable"
Heading 1Heading 2Heading 3Heading 4
Data 11Data 12Data 13Data 14
Data 21Data 22Data 23Data 24
Data 31Data 23Data 33Data 43
Svelte
<Table {headers} {data} {keys} space="compact" />
<Table {headers} {data} {keys} space="comfortable" />

Stripe Rows

The stripe prop adds alternating background colors to table rows, improving readability and visual distinction between rows. By default, this feature is disabled (undefined), meaning all rows have the same background.

  • "even" - Applies striping to even-numbered rows, making them visually distinct from odd rows.
  • "odd" Applies striping to odd-numbered rows, enhancing readability by differentiating them from even rows.
  • Custom class names - You can specify a class name instead of predefined values to apply custom styling. This allows full control over the appearance of striped rows, making it easy to match your design needs.
Striped even rows: stripe="even"
Heading 1Heading 2Heading 3Heading 4
Data 11Data 12Data 13Data 14
Data 21Data 22Data 23Data 24
Data 31Data 23Data 33Data 43
Striped odd rows: stripe="odd"
Heading 1Heading 2Heading 3Heading 4
Data 11Data 12Data 13Data 14
Data 21Data 22Data 23Data 24
Data 31Data 23Data 33Data 43
Striped even rows with custom classes: stripe="<CUSTOM CLASSES>"
Heading 1Heading 2Heading 3Heading 4
Data 11Data 12Data 13Data 14
Data 21Data 22Data 23Data 24
Data 31Data 23Data 33Data 43
Striped odd rows with custom classes: stripe="<CUSTOM CLASSES>"
Heading 1Heading 2Heading 3Heading 4
Data 11Data 12Data 13Data 14
Data 21Data 22Data 23Data 24
Data 31Data 23Data 33Data 43
Svelte
<!-- Striped even rows -->
<Table {headers} {data} {keys} stripe="even" />
<!-- Striped odd rows -->
<Table {headers} {data} {keys} stripe="odd" />
<!-- Striped even rows with custom classes -->
<Table {headers} {data} {keys} stripe="even:bg-green-100 dark:even:bg-green-900" />
<!-- Striped odd rows with custom classes -->
<Table {headers} {data} {keys} stripe="odd:bg-green-100 dark:odd:bg-green-900" />

Hoverable Rows

The hover prop enables a visual highlight effect when users hover over table rows. By default, this feature is disabled (undefined), meaning no hover effect is applied.

  • true - When set to true, the row background color changes on hover, improving user experience and readability.
  • Custom class names - Instead of using the default hover effect, you can pass a custom class to define your own hover styles, allowing for more design flexibility.

Use the animationSpeed prop to control how fast the hover color changes. Available values are "none", "slower", "slow", "normal" (default), "fast" and "faster".

Hoverable rows: hover={true}
Heading 1Heading 2Heading 3Heading 4
Data 11Data 12Data 13Data 14
Data 21Data 22Data 23Data 24
Data 31Data 23Data 33Data 43
Hoverable rows with custom classes: hover="<CUSTOM CLASSES>"
Heading 1Heading 2Heading 3Heading 4
Data 11Data 12Data 13Data 14
Data 21Data 22Data 23Data 24
Data 31Data 23Data 33Data 43
Svelte
<!-- Hoverable rows -->
<Table {headers} {data} {keys} hover={true} />
<!-- Hoverable rows with custom classes -->
<Table {headers} {data} {keys} hover="hover:bg-red-100" />
<!-- Slower hover transition -->
<Table {headers} {data} {keys} hover={true} animationSpeed="slower" />

Customization

You can use the following props to customize the table's appearance, allowing you to style the table and its elements as needed.

  • borderColor - the border color for the table. The default is "border-gray-200/80 dark:border-gray-800/80", which reads in both light and dark mode. Override it with any Tailwind border color class.
  • trHeadClasses - Adds custom classes to the table header row ((<tr> inside <thead>)). This allows you to style the header separately, such as applying background colors, text styles, or spacing adjustments.
  • trClasses - Applies custom classes to all table body rows (<tr> inside <tbody>). Use this to control row styling, such as padding, text alignment, or hover effects.
  • thClasses - Adds custom classes to all table header cells (<th>), enabling control over the header text size, padding, alignment, or other styles.
  • tdClasses - Adds custom classes to all table cells (<td>), enabling precise control over text size, padding, alignment, or other styles.

Accessibility

A data table is read cell by cell, so a screen reader has to know which header each cell belongs to. Build the table from headers and data and that is handled: every header cell is written as <th scope="col">.

Writing the rows yourself works the same way, because TH now sets scope="col" on its own. Change it to scope="row" on a header cell that names its row, such as the first cell of each line in a comparison table.

A header cell that names its row
<TR>
  <TH scope="row">Starter</TH>
  <TD>$9</TD>
  <TD>3 projects</TD>
</TR>

Give the table a name with ariaLabel, or write a <caption> as the first thing inside it. Screen readers list the tables on a page, and an unnamed one is listed as nothing but "table".

Naming the table
<Table ariaLabel="Pricing plans" {headers} {data} />

A table wider than its container scrolls sideways. That box is a tab stop while it overflows, so people who do not use a mouse can scroll it with the arrow keys, and it is announced as a region using the name from ariaLabel. When the table fits, the tab stop disappears again, so it never adds a stop for nothing.

Two things are still yours to get right: keep the header row in a THead rather than styling the first body row to look like one, and do not use a table for layout, since everything in it is announced as data.

Configuration

Table

Table Head

Table Body

Table Row

Table Header Cell