Back to Prisma

Table

apps/eclipse/content/design-system/components/table.mdx

latest16.7 KB
Original Source

import { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption } from "@prisma/eclipse";

Usage

Basic Table

tsx
import { 
  Table, 
  TableHeader, 
  TableBody, 
  TableHead, 
  TableRow, 
  TableCell 
} from "@prisma/eclipse";

export function BasicTable() {
  return (
    <Table>
      <TableHeader>
        <TableRow>
          <TableHead>Name</TableHead>
          <TableHead>Type</TableHead>
          <TableHead>Description</TableHead>
        </TableRow>
      </TableHeader>
      <TableBody>
        <TableRow>
          <TableCell>id</TableCell>
          <TableCell>String</TableCell>
          <TableCell>Unique identifier</TableCell>
        </TableRow>
        <TableRow>
          <TableCell>name</TableCell>
          <TableCell>String</TableCell>
          <TableCell>User's full name</TableCell>
        </TableRow>
        <TableRow>
          <TableCell>email</TableCell>
          <TableCell>String</TableCell>
          <TableCell>User's email address</TableCell>
        </TableRow>
      </TableBody>
    </Table>
  );
}

Live Example:

<Table> <TableHeader> <TableRow> <TableHead>Name</TableHead> <TableHead>Type</TableHead> <TableHead>Description</TableHead> </TableRow> </TableHeader> <TableBody> <TableRow> <TableCell>id</TableCell> <TableCell>String</TableCell> <TableCell>Unique identifier</TableCell> </TableRow> <TableRow> <TableCell>name</TableCell> <TableCell>String</TableCell> <TableCell>User's full name</TableCell> </TableRow> <TableRow> <TableCell>email</TableCell> <TableCell>String</TableCell> <TableCell>User's email address</TableCell> </TableRow> </TableBody> </Table>

Markdown Table Syntax

Tables written in markdown are automatically converted to use the Table component:

md
| Name  | Type   | Description          |
|-------|--------|----------------------|
| id    | String | Unique identifier    |
| name  | String | User's full name     |
| email | String | User's email address |

Live Example:

FieldTypeDescription
idStringUnique identifier
nameStringUser's full name
emailStringUser's email address

Table with Caption

tsx
import { 
  Table, 
  TableHeader, 
  TableBody, 
  TableHead, 
  TableRow, 
  TableCell,
  TableCaption 
} from "@prisma/eclipse";

export function TableWithCaption() {
  return (
    <Table>
      <TableCaption>User database schema</TableCaption>
      <TableHeader>
        <TableRow>
          <TableHead>Down the rabbit hole</TableHead>
        </TableRow>
      </TableHeader>
      <TableHeader>
        <TableRow>
          <TableHead>Field</TableHead>
          <TableHead>Type</TableHead>
          <TableHead>Required</TableHead>
        </TableRow>
      </TableHeader>
      <TableBody>
        <TableRow>
          <TableCell>id</TableCell>
          <TableCell>Int</TableCell>
          <TableCell>Yes</TableCell>
        </TableRow>
        <TableRow>
          <TableCell>email</TableCell>
          <TableCell>String</TableCell>
          <TableCell>Yes</TableCell>
        </TableRow>
        <TableRow>
          <TableCell>avatar</TableCell>
          <TableCell>String</TableCell>
          <TableCell>No</TableCell>
        </TableRow>
      </TableBody>
    </Table>
  );
}

Live Example:

<Table> <TableCaption>User database schema</TableCaption> <TableHeader> <TableRow> <TableHead colSpan="3">Down the rabbit hole</TableHead> </TableRow> </TableHeader> <TableHeader> <TableRow> <TableHead>Field</TableHead> <TableHead>Type</TableHead> <TableHead>Required</TableHead> </TableRow> </TableHeader> <TableBody> <TableRow> <TableCell>id</TableCell> <TableCell>Int</TableCell> <TableCell>Yes</TableCell> </TableRow> <TableRow> <TableCell>email</TableCell> <TableCell>String</TableCell> <TableCell>Yes</TableCell> </TableRow> <TableRow> <TableCell>avatar</TableCell> <TableCell>String</TableCell> <TableCell>No</TableCell> </TableRow> </TableBody> </Table>

Table with Footer

tsx
import { 
  Table, 
  TableHeader, 
  TableBody,
  TableFooter, 
  TableHead, 
  TableRow, 
  TableCell 
} from "@prisma/eclipse";

export function TableWithFooter() {
  return (
    <Table>
      <TableHeader>
        <TableRow>
          <TableHead>Product</TableHead>
          <TableHead>Quantity</TableHead>
          <TableHead className="text-right">Price</TableHead>
        </TableRow>
      </TableHeader>
      <TableBody>
        <TableRow>
          <TableCell>Prisma ORM</TableCell>
          <TableCell>1</TableCell>
          <TableCell className="text-right">$0</TableCell>
        </TableRow>
        <TableRow>
          <TableCell>Prisma Accelerate</TableCell>
          <TableCell>1</TableCell>
          <TableCell className="text-right">$29</TableCell>
        </TableRow>
        <TableRow>
          <TableCell>Prisma Pulse</TableCell>
          <TableCell>1</TableCell>
          <TableCell className="text-right">$99</TableCell>
        </TableRow>
      </TableBody>
      <TableFooter>
        <TableRow>
          <TableCell colSpan={2}>Total</TableCell>
          <TableCell className="text-right">$128</TableCell>
        </TableRow>
      </TableFooter>
    </Table>
  );
}

Live Example:

<Table> <TableHeader> <TableRow> <TableHead>Product</TableHead> <TableHead>Quantity</TableHead> <TableHead className="text-right">Price</TableHead> </TableRow> </TableHeader> <TableBody> <TableRow> <TableCell>Prisma ORM</TableCell> <TableCell>1</TableCell> <TableCell className="text-right">$0</TableCell> </TableRow> <TableRow> <TableCell>Prisma Accelerate</TableCell> <TableCell>1</TableCell> <TableCell className="text-right">$29</TableCell> </TableRow> <TableRow> <TableCell>Prisma Pulse</TableCell> <TableCell>1</TableCell> <TableCell className="text-right">$99</TableCell> </TableRow> </TableBody> <TableFooter> <TableRow> <TableCell colSpan={2}>Total</TableCell> <TableCell className="text-right">$128</TableCell> </TableRow> </TableFooter> </Table>

Alignment Options

tsx
import { 
  Table, 
  TableHeader, 
  TableBody, 
  TableHead, 
  TableRow, 
  TableCell 
} from "@prisma/eclipse";

export function AlignedTable() {
  return (
    <Table>
      <TableHeader>
        <TableRow>
          <TableHead className="text-left">Left Aligned</TableHead>
          <TableHead className="text-center">Center Aligned</TableHead>
          <TableHead className="text-right">Right Aligned</TableHead>
        </TableRow>
      </TableHeader>
      <TableBody>
        <TableRow>
          <TableCell className="text-left">Default</TableCell>
          <TableCell className="text-center">Centered</TableCell>
          <TableCell className="text-right">100</TableCell>
        </TableRow>
        <TableRow>
          <TableCell className="text-left">Text</TableCell>
          <TableCell className="text-center">Content</TableCell>
          <TableCell className="text-right">200</TableCell>
        </TableRow>
      </TableBody>
    </Table>
  );
}

Live Example:

<Table> <TableHeader> <TableRow> <TableHead className="text-left">Left Aligned</TableHead> <TableHead className="text-center">Center Aligned</TableHead> <TableHead className="text-right">Right Aligned</TableHead> </TableRow> </TableHeader> <TableBody> <TableRow> <TableCell className="text-left">Default</TableCell> <TableCell className="text-center">Centered</TableCell> <TableCell className="text-right">100</TableCell> </TableRow> <TableRow> <TableCell className="text-left">Text</TableCell> <TableCell className="text-center">Content</TableCell> <TableCell className="text-right">200</TableCell> </TableRow> </TableBody> </Table>

Component Props

Table

  • className - Additional CSS classes (optional)
  • children - Table content (required)
  • All standard HTML table attributes are supported

TableHeader

  • className - Additional CSS classes (optional)
  • children - Header rows (required)
  • All standard HTML thead attributes are supported

TableBody

  • className - Additional CSS classes (optional)
  • children - Body rows (required)
  • All standard HTML tbody attributes are supported

TableFooter

  • className - Additional CSS classes (optional)
  • children - Footer rows (required)
  • All standard HTML tfoot attributes are supported

TableRow

  • className - Additional CSS classes (optional)
  • children - Table cells (required)
  • All standard HTML tr attributes are supported

TableHead

  • className - Additional CSS classes (optional)
  • children - Header content (required)
  • All standard HTML th attributes are supported (colSpan, rowSpan, etc.)

TableCell

  • className - Additional CSS classes (optional)
  • children - Cell content (required)
  • All standard HTML td attributes are supported (colSpan, rowSpan, etc.)

TableCaption

  • className - Additional CSS classes (optional)
  • children - Caption text (required)
  • All standard HTML caption attributes are supported

Features

  • ✅ Responsive with horizontal scrolling on overflow
  • ✅ Hover states on table rows
  • ✅ Border styling with Eclipse design tokens
  • ✅ Support for header, body, and footer sections
  • ✅ Optional caption for accessibility
  • ✅ Customizable alignment (left, center, right)
  • ✅ Support for colspan and rowspan
  • ✅ Semantic HTML structure
  • ✅ Accessible by default
  • ✅ Works with markdown table syntax

Best Practices

  • Use TableHeader for column headings to improve accessibility
  • Use TableCaption to provide context about the table's content
  • Align numbers to the right for better readability
  • Keep tables simple - avoid nesting tables
  • Use consistent column widths when possible
  • Consider mobile responsiveness - tables scroll horizontally
  • Use meaningful header text that describes the column data
  • Add hover states for better user experience (built-in)
  • Use TableFooter for summary rows or totals
  • Avoid overly complex tables - break them into multiple simple tables if needed

Common Patterns

API Reference Table

tsx
<Table>
  <TableCaption>Prisma Client API methods</TableCaption>
  <TableHeader>
    <TableRow>
      <TableHead>Method</TableHead>
      <TableHead>Description</TableHead>
      <TableHead>Returns</TableHead>
    </TableRow>
  </TableHeader>
  <TableBody>
    <TableRow>
      <TableCell><code>findMany()</code></TableCell>
      <TableCell>Fetch multiple records</TableCell>
      <TableCell>Array</TableCell>
    </TableRow>
    <TableRow>
      <TableCell><code>findUnique()</code></TableCell>
      <TableCell>Fetch a single record</TableCell>
      <TableCell>Object or null</TableCell>
    </TableRow>
    <TableRow>
      <TableCell><code>create()</code></TableCell>
      <TableCell>Create a new record</TableCell>
      <TableCell>Object</TableCell>
    </TableRow>
  </TableBody>
</Table>

Pricing Table

tsx
<Table>
  <TableHeader>
    <TableRow>
      <TableHead>Plan</TableHead>
      <TableHead>Features</TableHead>
      <TableHead className="text-right">Price</TableHead>
    </TableRow>
  </TableHeader>
  <TableBody>
    <TableRow>
      <TableCell className="font-semibold">Free</TableCell>
      <TableCell>Basic features</TableCell>
      <TableCell className="text-right">$0/mo</TableCell>
    </TableRow>
    <TableRow>
      <TableCell className="font-semibold">Pro</TableCell>
      <TableCell>Advanced features</TableCell>
      <TableCell className="text-right">$29/mo</TableCell>
    </TableRow>
    <TableRow>
      <TableCell className="font-semibold">Enterprise</TableCell>
      <TableCell>All features + support</TableCell>
      <TableCell className="text-right">Custom</TableCell>
    </TableRow>
  </TableBody>
</Table>

Comparison Table

tsx
<Table>
  <TableHeader>
    <TableRow>
      <TableHead>Feature</TableHead>
      <TableHead className="text-center">Prisma ORM</TableHead>
      <TableHead className="text-center">Other ORMs</TableHead>
    </TableRow>
  </TableHeader>
  <TableBody>
    <TableRow>
      <TableCell>Type Safety</TableCell>
      <TableCell className="text-center"></TableCell>
      <TableCell className="text-center"></TableCell>
    </TableRow>
    <TableRow>
      <TableCell>Auto-completion</TableCell>
      <TableCell className="text-center"></TableCell>
      <TableCell className="text-center">⚠️</TableCell>
    </TableRow>
    <TableRow>
      <TableCell>Migrations</TableCell>
      <TableCell className="text-center"></TableCell>
      <TableCell className="text-center"></TableCell>
    </TableRow>
  </TableBody>
</Table>

Status Table

tsx
<Table>
  <TableHeader>
    <TableRow>
      <TableHead>Service</TableHead>
      <TableHead>Status</TableHead>
      <TableHead>Uptime</TableHead>
    </TableRow>
  </TableHeader>
  <TableBody>
    <TableRow>
      <TableCell>Prisma Data Platform</TableCell>
      <TableCell>
        <span className="inline-flex items-center gap-1 text-foreground-success">
          <span className="size-2 rounded-full bg-foreground-success" />
          Operational
        </span>
      </TableCell>
      <TableCell>99.9%</TableCell>
    </TableRow>
    <TableRow>
      <TableCell>Prisma Accelerate</TableCell>
      <TableCell>
        <span className="inline-flex items-center gap-1 text-foreground-success">
          <span className="size-2 rounded-full bg-foreground-success" />
          Operational
        </span>
      </TableCell>
      <TableCell>99.99%</TableCell>
    </TableRow>
  </TableBody>
</Table>

Accessibility

  • Use <TableHeader> for proper table header semantics
  • Use <TableCaption> to describe table content for screen readers
  • Tables are keyboard navigable
  • Proper HTML table structure ensures screen reader compatibility
  • Use meaningful header text that describes column content
  • Avoid using tables for layout purposes
  • Consider adding scope attribute to header cells for complex tables
  • Ensure sufficient color contrast in table content

Responsive Behavior

The Table component automatically handles overflow:

  • Tables are wrapped in a scrollable container
  • Horizontal scrolling is enabled when content exceeds viewport width
  • No content is hidden or truncated
  • Scroll behavior is smooth and native
  • Mobile-friendly touch scrolling

For better mobile experience, consider:

  • Reducing the number of columns on small screens
  • Using a card layout instead of a table for very small screens
  • Making column widths responsive
  • Prioritizing essential data in leftmost columns

Styling Guidelines

The Table component follows Eclipse design system principles:

  • Borders: Subtle borders between rows and sections
  • Hover: Smooth hover states on rows
  • Spacing: Consistent padding (p-2) in cells
  • Typography: Small font size (text-sm) for density
  • Alignment: Left-aligned by default, customizable per cell
  • Colors: Uses muted colors for backgrounds and borders

Override styles as needed:

tsx
<Table className="text-base">
  <TableHeader className="bg-background-neutral">
    <TableRow className="hover:bg-background-neutral-strong">
      <TableHead className="font-bold p-4">Custom Styling</TableHead>
    </TableRow>
  </TableHeader>
</Table>

Integration with Data

With Static Data

tsx
const users = [
  { id: 1, name: "Alice", email: "[email protected]" },
  { id: 2, name: "Bob", email: "[email protected]" },
];

<Table>
  <TableHeader>
    <TableRow>
      <TableHead>Name</TableHead>
      <TableHead>Email</TableHead>
    </TableRow>
  </TableHeader>
  <TableBody>
    {users.map((user) => (
      <TableRow key={user.id}>
        <TableCell>{user.name}</TableCell>
        <TableCell>{user.email}</TableCell>
      </TableRow>
    ))}
  </TableBody>
</Table>

With Dynamic Data

tsx
import { useQuery } from "@tanstack/react-query";

export function UserTable() {
  const { data, isLoading } = useQuery({
    queryKey: ['users'],
    queryFn: fetchUsers,
  });

  if (isLoading) return <div>Loading...</div>;

  return (
    <Table>
      <TableHeader>
        <TableRow>
          <TableHead>Name</TableHead>
          <TableHead>Email</TableHead>
          <TableHead>Role</TableHead>
        </TableRow>
      </TableHeader>
      <TableBody>
        {data?.map((user) => (
          <TableRow key={user.id}>
            <TableCell>{user.name}</TableCell>
            <TableCell>{user.email}</TableCell>
            <TableCell>{user.role}</TableCell>
          </TableRow>
        ))}
      </TableBody>
    </Table>
  );
}