Components
Table

Table

A component that displays data in a tabular format.

Usage

Product Inventory
IDNameStockPrice
P001MacBook Pro12$1999.00
P002AirPods Pro25$249.00
P003Leather Wallet50$79.00
Totals87$34,163.00
import * as Table from '~/components/ui/table'

export const Demo = (props: Table.RootProps) => {
  return (
    <Table.Root {...props}>
      <Table.Caption>Product Inventory</Table.Caption>
      <Table.Head>
        <Table.Row>
          <Table.Header>ID</Table.Header>
          <Table.Header>Name</Table.Header>
          <Table.Header>Stock</Table.Header>
          <Table.Header textAlign="right">Price</Table.Header>
        </Table.Row>
      </Table.Head>
      <Table.Body>
        {productData.map((product, index) => (
          <Table.Row key={index}>
            <Table.Cell fontWeight="medium">{product.id}</Table.Cell>
            <Table.Cell>{product.name}</Table.Cell>
            <Table.Cell>{product.stock}</Table.Cell>
            <Table.Cell textAlign="right">{product.price}</Table.Cell>
          </Table.Row>
        ))}
      </Table.Body>
      <Table.Footer>
        <Table.Row>
          <Table.Cell colSpan={2}>Totals</Table.Cell>
          <Table.Cell>87</Table.Cell>
          <Table.Cell textAlign="right">$34,163.00</Table.Cell>
        </Table.Row>
      </Table.Footer>
    </Table.Root>
  )
}

const productData = [
  { id: 'P001', name: 'MacBook Pro', stock: 12, price: '$1999.00' },
  { id: 'P002', name: 'AirPods Pro', stock: 25, price: '$249.00' },
  { id: 'P003', name: 'Leather Wallet', stock: 50, price: '$79.00' },
]

Installation

1

Add Component

Insert code snippet into your project. Update import paths as needed.

import { ark } from '@ark-ui/react/factory'
import type { ComponentProps } from 'react'
import { styled } from 'styled-system/jsx'
import { table } from 'styled-system/recipes'
import { createStyleContext } from '~/lib/create-style-context'

const { withProvider, withContext } = createStyleContext(table)

export const Root = withProvider(styled(ark.table), 'root')
export const Body = withContext(styled(ark.tbody), 'body')
export const Caption = withContext(styled(ark.caption), 'caption')
export const Cell = withContext(styled(ark.td), 'cell')
export const Footer = withContext(styled(ark.tfoot), 'footer')
export const Head = withContext(styled(ark.thead), 'head')
export const Header = withContext(styled(ark.th), 'header')
export const Row = withContext(styled(ark.tr), 'row')

export interface RootProps extends ComponentProps<typeof Root> {}
export interface BodyProps extends ComponentProps<typeof Body> {}
export interface CaptionProps extends ComponentProps<typeof Caption> {}
export interface CellProps extends ComponentProps<typeof Cell> {}
export interface FooterProps extends ComponentProps<typeof Footer> {}
export interface HeadProps extends ComponentProps<typeof Head> {}
export interface HeaderProps extends ComponentProps<typeof Header> {}
export interface RowProps extends ComponentProps<typeof Row> {}
2

Add Recipe

This step is necessary only if you do not use any of the Park UI plugins.

import { defineSlotRecipe } from '@pandacss/dev'

export const table = defineSlotRecipe({
  className: 'table',
  slots: ['root', 'body', 'cell', 'footer', 'head', 'header', 'row', 'caption'],
  base: {
    root: {
      captionSide: 'bottom',
      width: 'full',
    },
    body: {
      '& tr:last-child': {
        borderBottomWidth: '0',
      },
    },
    caption: {
      color: 'fg.subtle',
    },
    cell: {
      verticalAlign: 'middle',
    },
    footer: {
      fontWeight: 'medium',
      borderTopWidth: '1px',
      '& tr:last-child': {
        borderBottomWidth: '0',
      },
    },
    header: {
      color: 'fg.muted',
      fontWeight: 'medium',
      textAlign: 'left',
      verticalAlign: 'middle',
    },
    row: {
      borderBottomWidth: '1px',
      transitionDuration: 'normal',
      transitionProperty: 'background, color',
      transitionTimingFunction: 'default',
    },
  },
  defaultVariants: {
    size: 'md',
    variant: 'plain',
  },
  variants: {
    variant: {
      outline: {
        root: {
          borderWidth: '1px',
        },
        head: {
          bg: 'bg.subtle',
        },
      },
      plain: {
        row: {
          _hover: {
            bg: 'bg.subtle',
          },
          _selected: {
            bg: 'bg.muted',
          },
        },
      },
    },
    size: {
      sm: {
        root: {
          textStyle: 'sm',
        },
        caption: {
          mt: '4',
        },
        cell: {
          height: '11',
          px: '3',
        },
        header: {
          height: '11',
          px: '3',
        },
      },
      md: {
        root: {
          textStyle: 'sm',
        },
        caption: {
          mt: '4',
        },
        cell: {
          height: '14',
          px: '4',
        },
        header: {
          height: '11',
          px: '4',
        },
      },
    },
  },
})

On this page