table

Table can be used to show a list of data in a table format.

Base Table

The base table component:

Exported source
table = SingleValueFactory("table", "Table component for displaying data in rows and columns") # Table component

Table Modifiers

Table modifier utilities:

Exported source
table_modifiers = SimpleFactory(
    {
        "zebra": "table-zebra",
        "pin_rows": "table-pin-rows",
        "pin_cols": "table-pin-cols"
    },
    "Table modifiers (zebra stripes, sticky rows/columns)"
) # Table modifiers

Table Sizes

Table size variants:

Exported source
table_sizes = enums_to_simple_factory(table, [DaisyUINamedSize], "Table size variants from extra small to extra large") # Table size variants

Table Test Examples


source

test_table_basic_examples

 test_table_basic_examples ()

Test basic table utilities.

Exported source
def test_table_basic_examples():
    """Test basic table utilities."""
    # Basic component
    assert str(table) == "table"
    
    # With modifiers
    assert str(table.hover) == "hover:table"
    assert str(table.md) == "md:table"
    assert str(table.dark) == "dark:table"

# Run the tests
test_table_basic_examples()

source

test_table_modifiers_examples

 test_table_modifiers_examples ()

Test table modifier utilities.

Exported source
def test_table_modifiers_examples():
    """Test table modifier utilities."""
    assert str(table_modifiers.zebra) == "table-zebra"
    assert str(table_modifiers.pin_rows) == "table-pin-rows"
    assert str(table_modifiers.pin_cols) == "table-pin-cols"
    
    # With responsive modifiers
    assert str(table_modifiers.zebra.hover) == "hover:table-zebra"
    assert str(table_modifiers.pin_rows.md) == "md:table-pin-rows"

# Run the tests
test_table_modifiers_examples()

source

test_table_sizes_examples

 test_table_sizes_examples ()

Test table size variants.

Exported source
def test_table_sizes_examples():
    """Test table size variants."""
    assert str(table_sizes.xs) == "table-xs"
    assert str(table_sizes.sm) == "table-sm"
    assert str(table_sizes.md) == "table-md"
    assert str(table_sizes.lg) == "table-lg"
    assert str(table_sizes.xl) == "table-xl"
    
    # With responsive modifiers
    assert str(table_sizes.xs.sm) == "sm:table-xs"
    assert str(table_sizes.lg.md) == "md:table-lg"

# Run the tests
test_table_sizes_examples()

source

test_table_basic_fasthtml_examples

 test_table_basic_fasthtml_examples ()

Test basic table and table with border and background from daisyUI v5 documentation.

Exported source
def test_table_basic_fasthtml_examples():
    """Test basic table and table with border and background from daisyUI v5 documentation."""
    from fasthtml.common import Div, Table, Thead, Tbody, Tr, Th, Td
    from cjm_fasthtml_tailwind.utilities.layout import overflow
    from cjm_fasthtml_tailwind.utilities.borders import border
    from cjm_fasthtml_tailwind.core.base import combine_classes
    from cjm_fasthtml_daisyui.utilities.semantic_colors import bg_dui, border_dui
    from cjm_fasthtml_daisyui.utilities.border_radius import border_radius
    
    # Basic tablefrom cjm_fasthtml_daisyui.utilities.semantic_colors import bg_dui, border_dui,
    basic_table = Div(
        Table(
            Thead(
                Tr(
                    Th(),
                    Th("Name"),
                    Th("Job"),
                    Th("Favorite Color")
                )
            ),
            Tbody(
                Tr(
                    Th("1"),
                    Td("Cy Ganderton"),
                    Td("Quality Control Specialist"),
                    Td("Blue")
                ),
                Tr(
                    Th("2"),
                    Td("Hart Hagerty"),
                    Td("Desktop Support Technician"),
                    Td("Purple")
                ),
                Tr(
                    Th("3"),
                    Td("Brice Swyre"),
                    Td("Tax Accountant"),
                    Td("Red")
                )
            ),
            cls=str(table)
        ),
        cls=combine_classes(overflow.x.auto)
    )
    assert "overflow-x-auto" in basic_table.attrs['class']
    assert basic_table.children[0].tag == "table"
    assert "table" in basic_table.children[0].attrs['class']
    # Verify table structure
    thead = basic_table.children[0].children[0]
    
    assert thead.tag == "thead"
    assert thead.children[0].tag == "tr"
    assert len(thead.children[0].children) == 4  # 4 columns
    assert thead.children[0].children[0].tag == "th"
    assert thead.children[0].children[0].children == ()  # Empty first header
    assert thead.children[0].children[1].tag == "th"
    assert thead.children[0].children[1].children[0] == "Name"
    # Verify tbody
    tbody = basic_table.children[0].children[1]
    assert tbody.tag == "tbody"
    assert len(tbody.children) == 3  # 3 rows
    assert tbody.children[0].tag == "tr"
    assert tbody.children[0].children[0].tag == "th"
    assert tbody.children[0].children[0].children[0] == "1"
    assert tbody.children[0].children[1].tag == "td"
    assert tbody.children[0].children[1].children[0] == "Cy Ganderton"
    
    # Table with border and background
    bordered_table = Div(
        Table(
            Thead(
                Tr(
                    Th(),
                    Th("Name"),
                    Th("Job"),
                    Th("Favorite Color")
                )
            ),
            Tbody(
                Tr(
                    Th("1"),
                    Td("Cy Ganderton"),
                    Td("Quality Control Specialist"),
                    Td("Blue")
                ),
                Tr(
                    Th("2"),
                    Td("Hart Hagerty"),
                    Td("Desktop Support Technician"),
                    Td("Purple")
                ),
                Tr(
                    Th("3"),
                    Td("Brice Swyre"),
                    Td("Tax Accountant"),
                    Td("Red")
                )
            ),
            cls=str(table)
        ),
        cls=combine_classes(overflow.x.auto, border_radius.box, border(), border_dui.base_content.opacity(5), bg_dui.base_100)
    )
    assert "overflow-x-auto" in bordered_table.attrs['class']
    assert "rounded-box" in bordered_table.attrs['class']
    assert "border" in bordered_table.attrs['class']
    assert "border-base-content/5" in bordered_table.attrs['class']
    assert "bg-base-100" in bordered_table.attrs['class']
    assert bordered_table.children[0].tag == "table"
    assert "table" in bordered_table.children[0].attrs['class']
    # Verify it has same content as basic table but with border styling
    assert len(bordered_table.children[0].children[1].children) == 3  # 3 rows
    
    # Return all examples in a Div
    return Div(
        basic_table,
        bordered_table
    )

# Run the tests
test_table_basic_fasthtml_examples()
<div>
  <div class="overflow-x-auto">
    <table class="table">
      <thead>
        <tr>
          <th></th>
          <th>Name</th>
          <th>Job</th>
          <th>Favorite Color</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <th>1</th>
          <td>Cy Ganderton</td>
          <td>Quality Control Specialist</td>
          <td>Blue</td>
        </tr>
        <tr>
          <th>2</th>
          <td>Hart Hagerty</td>
          <td>Desktop Support Technician</td>
          <td>Purple</td>
        </tr>
        <tr>
          <th>3</th>
          <td>Brice Swyre</td>
          <td>Tax Accountant</td>
          <td>Red</td>
        </tr>
      </tbody>
    </table>
  </div>
  <div class="overflow-x-auto rounded-box border border-base-content/5 bg-base-100">
    <table class="table">
      <thead>
        <tr>
          <th></th>
          <th>Name</th>
          <th>Job</th>
          <th>Favorite Color</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <th>1</th>
          <td>Cy Ganderton</td>
          <td>Quality Control Specialist</td>
          <td>Blue</td>
        </tr>
        <tr>
          <th>2</th>
          <td>Hart Hagerty</td>
          <td>Desktop Support Technician</td>
          <td>Purple</td>
        </tr>
        <tr>
          <th>3</th>
          <td>Brice Swyre</td>
          <td>Tax Accountant</td>
          <td>Red</td>
        </tr>
      </tbody>
    </table>
  </div>
</div>
test_func = test_table_basic_fasthtml_examples
app, rt = create_test_app(theme=DaisyUITheme.LIGHT)

@rt
def index():
    return create_test_page(test_func.__doc__.title().replace('.', ''), test_func())
server = start_test_server(app)
display(HTMX())
server.stop()

source

test_table_style_fasthtml_examples

 test_table_style_fasthtml_examples ()

Test table with active row, hover row, and zebra stripes from daisyUI v5 documentation.

Exported source
def test_table_style_fasthtml_examples():
    """Test table with active row, hover row, and zebra stripes from daisyUI v5 documentation."""
    from fasthtml.common import Div, Table, Thead, Tbody, Tr, Th, Td
    from cjm_fasthtml_tailwind.utilities.layout import overflow
    from cjm_fasthtml_tailwind.core.base import combine_classes
    from cjm_fasthtml_daisyui.utilities.semantic_colors import bg_dui
    
    # Table with an active row
    active_row_table = Div(
        Table(
            Thead(
                Tr(
                    Th(),
                    Th("Name"),
                    Th("Job"),
                    Th("Favorite Color")
                )
            ),
            Tbody(
                Tr(
                    Th("1"),
                    Td("Cy Ganderton"),
                    Td("Quality Control Specialist"),
                    Td("Blue"),
                    cls=str(bg_dui.base_200)
                ),
                Tr(
                    Th("2"),
                    Td("Hart Hagerty"),
                    Td("Desktop Support Technician"),
                    Td("Purple")
                ),
                Tr(
                    Th("3"),
                    Td("Brice Swyre"),
                    Td("Tax Accountant"),
                    Td("Red")
                )
            ),
            cls=str(table)
        ),
        cls=combine_classes(overflow.x.auto)
    )
    assert "overflow-x-auto" in active_row_table.attrs['class']
    assert active_row_table.children[0].tag == "table"
    assert "table" in active_row_table.children[0].attrs['class']
    # Verify active row has bg-base-200
    tbody = active_row_table.children[0].children[1]
    assert tbody.tag == "tbody"
    assert "bg-base-200" in tbody.children[0].attrs['class']
    assert tbody.children[0].children[1].children[0] == "Cy Ganderton"
    # Other rows should not have bg-base-200
    assert 'class' not in tbody.children[1].attrs or "bg-base-200" not in tbody.children[1].attrs.get('class', '')
    assert 'class' not in tbody.children[2].attrs or "bg-base-200" not in tbody.children[2].attrs.get('class', '')
    
    # Table with a row that highlights on hover
    hover_table = Div(
        Table(
            Thead(
                Tr(
                    Th(),
                    Th("Name"),
                    Th("Job"),
                    Th("Favorite Color")
                )
            ),
            Tbody(
                Tr(
                    Th("1"),
                    Td("Cy Ganderton"),
                    Td("Quality Control Specialist"),
                    Td("Blue")
                ),
                Tr(
                    Th("2"),
                    Td("Hart Hagerty"),
                    Td("Desktop Support Technician"),
                    Td("Purple"),
                    cls=str(bg_dui.base_300.hover)
                ),
                Tr(
                    Th("3"),
                    Td("Brice Swyre"),
                    Td("Tax Accountant"),
                    Td("Red")
                )
            ),
            cls=str(table)
        ),
        cls=combine_classes(overflow.x.auto)
    )
    assert "overflow-x-auto" in hover_table.attrs['class']
    assert hover_table.children[0].tag == "table"
    assert "table" in hover_table.children[0].attrs['class']
    # Verify second row has hover:bg-base-300
    tbody = hover_table.children[0].children[1]
    assert tbody.tag == "tbody"
    assert "hover:bg-base-300" in tbody.children[1].attrs['class']
    assert tbody.children[1].children[1].children[0] == "Hart Hagerty"
    # Other rows should not have hover styling
    assert 'class' not in tbody.children[0].attrs or "hover:bg-base-300" not in tbody.children[0].attrs.get('class', '')
    assert 'class' not in tbody.children[2].attrs or "hover:bg-base-300" not in tbody.children[2].attrs.get('class', '')
    
    # Zebra striped table
    zebra_table = Div(
        Table(
            Thead(
                Tr(
                    Th(),
                    Th("Name"),
                    Th("Job"),
                    Th("Favorite Color")
                )
            ),
            Tbody(
                Tr(
                    Th("1"),
                    Td("Cy Ganderton"),
                    Td("Quality Control Specialist"),
                    Td("Blue")
                ),
                Tr(
                    Th("2"),
                    Td("Hart Hagerty"),
                    Td("Desktop Support Technician"),
                    Td("Purple")
                ),
                Tr(
                    Th("3"),
                    Td("Brice Swyre"),
                    Td("Tax Accountant"),
                    Td("Red")
                )
            ),
            cls=combine_classes(table, table_modifiers.zebra)
        ),
        cls=combine_classes(overflow.x.auto)
    )
    assert "overflow-x-auto" in zebra_table.attrs['class']
    assert zebra_table.children[0].tag == "table"
    assert "table" in zebra_table.children[0].attrs['class']
    assert "table-zebra" in zebra_table.children[0].attrs['class']
    # Verify all rows are present
    tbody = zebra_table.children[0].children[1]
    assert tbody.tag == "tbody"
    assert len(tbody.children) == 3
    assert tbody.children[0].children[1].children[0] == "Cy Ganderton"
    assert tbody.children[1].children[1].children[0] == "Hart Hagerty"
    assert tbody.children[2].children[1].children[0] == "Brice Swyre"
    
    # Return all examples in a Div
    return Div(
        active_row_table,
        hover_table,
        zebra_table
    )

# Run the tests
test_table_style_fasthtml_examples()
<div>
  <div class="overflow-x-auto">
    <table class="table">
      <thead>
        <tr>
          <th></th>
          <th>Name</th>
          <th>Job</th>
          <th>Favorite Color</th>
        </tr>
      </thead>
      <tbody>
        <tr class="bg-base-200">
          <th>1</th>
          <td>Cy Ganderton</td>
          <td>Quality Control Specialist</td>
          <td>Blue</td>
        </tr>
        <tr>
          <th>2</th>
          <td>Hart Hagerty</td>
          <td>Desktop Support Technician</td>
          <td>Purple</td>
        </tr>
        <tr>
          <th>3</th>
          <td>Brice Swyre</td>
          <td>Tax Accountant</td>
          <td>Red</td>
        </tr>
      </tbody>
    </table>
  </div>
  <div class="overflow-x-auto">
    <table class="table">
      <thead>
        <tr>
          <th></th>
          <th>Name</th>
          <th>Job</th>
          <th>Favorite Color</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <th>1</th>
          <td>Cy Ganderton</td>
          <td>Quality Control Specialist</td>
          <td>Blue</td>
        </tr>
        <tr class="hover:bg-base-300">
          <th>2</th>
          <td>Hart Hagerty</td>
          <td>Desktop Support Technician</td>
          <td>Purple</td>
        </tr>
        <tr>
          <th>3</th>
          <td>Brice Swyre</td>
          <td>Tax Accountant</td>
          <td>Red</td>
        </tr>
      </tbody>
    </table>
  </div>
  <div class="overflow-x-auto">
    <table class="table table-zebra">
      <thead>
        <tr>
          <th></th>
          <th>Name</th>
          <th>Job</th>
          <th>Favorite Color</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <th>1</th>
          <td>Cy Ganderton</td>
          <td>Quality Control Specialist</td>
          <td>Blue</td>
        </tr>
        <tr>
          <th>2</th>
          <td>Hart Hagerty</td>
          <td>Desktop Support Technician</td>
          <td>Purple</td>
        </tr>
        <tr>
          <th>3</th>
          <td>Brice Swyre</td>
          <td>Tax Accountant</td>
          <td>Red</td>
        </tr>
      </tbody>
    </table>
  </div>
</div>
test_func = test_table_style_fasthtml_examples
app, rt = create_test_app(theme=DaisyUITheme.LIGHT)

@rt
def index():
    return create_test_page(test_func.__doc__.title().replace('.', ''), test_func())
server = start_test_server(app)
display(HTMX())
server.stop()

source

test_table_visual_elements_fasthtml_examples

 test_table_visual_elements_fasthtml_examples ()

Test table with visual elements from daisyUI v5 documentation.

Exported source
def test_table_visual_elements_fasthtml_examples():
    """Test table with visual elements from daisyUI v5 documentation."""
    from fasthtml.common import Div, Table, Thead, Tbody, Tr, Th, Td, Tfoot, Input, Button, Img, Span, Label, Br
    from cjm_fasthtml_tailwind.utilities.layout import display_tw, overflow
    from cjm_fasthtml_tailwind.utilities.flexbox_and_grid import items, gap, flex_display
    from cjm_fasthtml_tailwind.utilities.sizing import h, w
    from cjm_fasthtml_tailwind.utilities.typography import font_size, font_weight, font_family, text_color
    from cjm_fasthtml_tailwind.utilities.effects import opacity
    from cjm_fasthtml_tailwind.core.base import combine_classes
    from cjm_fasthtml_daisyui.components.actions.button import btn, btn_styles, btn_sizes
    from cjm_fasthtml_daisyui.components.data_display.badge import badge, badge_styles, badge_sizes
    from cjm_fasthtml_daisyui.components.data_display.avatar import avatar
    from cjm_fasthtml_daisyui.components.data_input.checkbox import checkbox as checkbox_factory
    from cjm_fasthtml_daisyui.components.layout.mask import mask, mask_styles
    
    # Table with visual elements
    visual_table = Div(
        Table(
            Thead(
                Tr(
                    Th(
                        Label(
                            Input(type="checkbox", cls=str(checkbox_factory))
                        )
                    ),
                    Th("Name"),
                    Th("Job"),
                    Th("Favorite Color"),
                    Th()
                )
            ),
            Tbody(
                Tr(
                    Th(
                        Label(
                            Input(type="checkbox", cls=str(checkbox_factory))
                        )
                    ),
                    Td(
                        Div(
                            Div(
                                Div(
                                    Img(
                                        src="https://img.daisyui.com/images/profile/demo/2@94.webp",
                                        alt="Avatar Tailwind CSS Component"
                                    ),
                                    cls=combine_classes(mask, mask_styles.squircle, h._12, w._12)
                                ),
                                cls=str(avatar)
                            ),
                            Div(
                                Div("Hart Hagerty", cls=str(font_weight.bold)),
                                Div("United States", cls=combine_classes(font_size.sm, opacity._50))
                            ),
                            cls=combine_classes(flex_display, items.center, gap._3)
                        )
                    ),
                    Td(
                        "Zemlak, Daniel and Leannon",
                        Br(),
                        Span("Desktop Support Technician", cls=combine_classes(badge, badge_styles.ghost, badge_sizes.sm))
                    ),
                    Td("Purple"),
                    Th(
                        Button("details", cls=combine_classes(btn, btn_styles.ghost, btn_sizes.xs))
                    )
                ),
                Tr(
                    Th(
                        Label(
                            Input(type="checkbox", cls=str(checkbox_factory))
                        )
                    ),
                    Td(
                        Div(
                            Div(
                                Div(
                                    Img(
                                        src="https://img.daisyui.com/images/profile/demo/3@94.webp",
                                        alt="Avatar Tailwind CSS Component"
                                    ),
                                    cls=combine_classes(mask, mask_styles.squircle, h._12, w._12)
                                ),
                                cls=str(avatar)
                            ),
                            Div(
                                Div("Brice Swyre", cls=str(font_weight.bold)),
                                Div("China", cls=combine_classes(font_size.sm, opacity._50))
                            ),
                            cls=combine_classes(flex_display, items.center, gap._3)
                        )
                    ),
                    Td(
                        "Carroll Group",
                        Br(),
                        Span("Tax Accountant", cls=combine_classes(badge, badge_styles.ghost, badge_sizes.sm))
                    ),
                    Td("Red"),
                    Th(
                        Button("details", cls=combine_classes(btn, btn_styles.ghost, btn_sizes.xs))
                    )
                ),
                Tr(
                    Th(
                        Label(
                            Input(type="checkbox", cls=str(checkbox_factory))
                        )
                    ),
                    Td(
                        Div(
                            Div(
                                Div(
                                    Img(
                                        src="https://img.daisyui.com/images/profile/demo/4@94.webp",
                                        alt="Avatar Tailwind CSS Component"
                                    ),
                                    cls=combine_classes(mask, mask_styles.squircle, h._12, w._12)
                                ),
                                cls=str(avatar)
                            ),
                            Div(
                                Div("Marjy Ferencz", cls=str(font_weight.bold)),
                                Div("Russia", cls=combine_classes(font_size.sm, opacity._50))
                            ),
                            cls=combine_classes(flex_display, items.center, gap._3)
                        )
                    ),
                    Td(
                        "Rowe-Schoen",
                        Br(),
                        Span("Office Assistant I", cls=combine_classes(badge, badge_styles.ghost, badge_sizes.sm))
                    ),
                    Td("Crimson"),
                    Th(
                        Button("details", cls=combine_classes(btn, btn_styles.ghost, btn_sizes.xs))
                    )
                ),
                Tr(
                    Th(
                        Label(
                            Input(type="checkbox", cls=str(checkbox_factory))
                        )
                    ),
                    Td(
                        Div(
                            Div(
                                Div(
                                    Img(
                                        src="https://img.daisyui.com/images/profile/demo/5@94.webp",
                                        alt="Avatar Tailwind CSS Component"
                                    ),
                                    cls=combine_classes(mask, mask_styles.squircle, h._12, w._12)
                                ),
                                cls=str(avatar)
                            ),
                            Div(
                                Div("Yancy Tear", cls=str(font_weight.bold)),
                                Div("Brazil", cls=combine_classes(font_size.sm, opacity._50))
                            ),
                            cls=combine_classes(flex_display, items.center, gap._3)
                        )
                    ),
                    Td(
                        "Wyman-Ledner",
                        Br(),
                        Span("Community Outreach Specialist", cls=combine_classes(badge, badge_styles.ghost, badge_sizes.sm))
                    ),
                    Td("Indigo"),
                    Th(
                        Button("details", cls=combine_classes(btn, btn_styles.ghost, btn_sizes.xs))
                    )
                )
            ),
            Tfoot(
                Tr(
                    Th(),
                    Th("Name"),
                    Th("Job"),
                    Th("Favorite Color"),
                    Th()
                )
            ),
            cls=str(table)
        ),
        cls=combine_classes(overflow.x.auto)
    )
    
    # Verify table structure
    assert "overflow-x-auto" in visual_table.attrs['class']
    assert visual_table.children[0].tag == "table"
    assert "table" in visual_table.children[0].attrs['class']
    
    # Verify thead
    thead = visual_table.children[0].children[0]
    assert thead.tag == "thead"
    assert thead.children[0].tag == "tr"
    assert len(thead.children[0].children) == 5  # 5 columns
    # First column has checkbox
    assert thead.children[0].children[0].tag == "th"
    assert thead.children[0].children[0].children[0].tag == "label"
    assert thead.children[0].children[0].children[0].children[0].tag == "input"
    assert thead.children[0].children[0].children[0].children[0].attrs['type'] == "checkbox"
    assert "checkbox" in thead.children[0].children[0].children[0].children[0].attrs['class']
    
    # Verify tbody
    tbody = visual_table.children[0].children[1]
    assert tbody.tag == "tbody"
    assert len(tbody.children) == 4  # 4 rows
    
    # Verify first row structure
    first_row = tbody.children[0]
    assert first_row.tag == "tr"
    assert len(first_row.children) == 5
    
    # Checkbox column
    assert first_row.children[0].tag == "th"
    assert first_row.children[0].children[0].tag == "label"
    assert first_row.children[0].children[0].children[0].tag == "input"
    assert "checkbox" in first_row.children[0].children[0].children[0].attrs['class']
    
    # Name column with avatar
    name_td = first_row.children[1]
    assert name_td.tag == "td"
    flex_container = name_td.children[0]
    assert "flex" in flex_container.attrs['class']
    assert "items-center" in flex_container.attrs['class']
    assert "gap-3" in flex_container.attrs['class']
    # Avatar
    avatar_div = flex_container.children[0]
    assert "avatar" in avatar_div.attrs['class']
    mask_div = avatar_div.children[0]
    assert "mask" in mask_div.attrs['class']
    assert "mask-squircle" in mask_div.attrs['class']
    assert "h-12" in mask_div.attrs['class']
    assert "w-12" in mask_div.attrs['class']
    assert mask_div.children[0].tag == "img"
    assert mask_div.children[0].attrs['src'] == "https://img.daisyui.com/images/profile/demo/2@94.webp"
    # Name text
    name_div = flex_container.children[1]
    assert name_div.children[0].children[0] == "Hart Hagerty"
    assert "font-bold" in name_div.children[0].attrs['class']
    assert name_div.children[1].children[0] == "United States"
    assert "text-sm" in name_div.children[1].attrs['class']
    assert "opacity-50" in name_div.children[1].attrs['class']
    
    # Job column with badge
    job_td = first_row.children[2]
    assert job_td.tag == "td"
    assert job_td.children[0] == "Zemlak, Daniel and Leannon"
    assert job_td.children[1].tag == "br"
    assert job_td.children[2].tag == "span"
    assert "badge" in job_td.children[2].attrs['class']
    assert "badge-ghost" in job_td.children[2].attrs['class']
    assert "badge-sm" in job_td.children[2].attrs['class']
    assert job_td.children[2].children[0] == "Desktop Support Technician"
    
    # Color column
    assert first_row.children[3].tag == "td"
    assert first_row.children[3].children[0] == "Purple"
    
    # Details button column
    assert first_row.children[4].tag == "th"
    assert first_row.children[4].children[0].tag == "button"
    assert "btn" in first_row.children[4].children[0].attrs['class']
    assert "btn-ghost" in first_row.children[4].children[0].attrs['class']
    assert "btn-xs" in first_row.children[4].children[0].attrs['class']
    assert first_row.children[4].children[0].children[0] == "details"
    
    # Verify second row has different data
    second_row = tbody.children[1]
    assert second_row.children[1].children[0].children[1].children[0].children[0] == "Brice Swyre"
    assert second_row.children[1].children[0].children[1].children[1].children[0] == "China"
    assert second_row.children[2].children[0] == "Carroll Group"
    assert second_row.children[2].children[2].children[0] == "Tax Accountant"
    
    # Verify tfoot
    tfoot = visual_table.children[0].children[2]
    assert tfoot.tag == "tfoot"
    assert tfoot.children[0].tag == "tr"
    assert len(tfoot.children[0].children) == 5  # 5 columns
    assert tfoot.children[0].children[1].children[0] == "Name"
    assert tfoot.children[0].children[2].children[0] == "Job"
    
    # Return the example in a Div
    return Div(visual_table)

# Run the tests
test_table_visual_elements_fasthtml_examples()
<div>
  <div class="overflow-x-auto">
    <table class="table">
      <thead>
        <tr>
          <th>
<label>              <input type="checkbox" class="checkbox">
</label>          </th>
          <th>Name</th>
          <th>Job</th>
          <th>Favorite Color</th>
          <th></th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <th>
<label>              <input type="checkbox" class="checkbox">
</label>          </th>
          <td>
            <div class="flex items-center gap-3">
              <div class="avatar">
                <div class="mask mask-squircle h-12 w-12">
<img src="https://img.daisyui.com/images/profile/demo/2@94.webp" alt="Avatar Tailwind CSS Component">                </div>
              </div>
              <div>
                <div class="font-bold">Hart Hagerty</div>
                <div class="text-sm opacity-50">United States</div>
              </div>
            </div>
          </td>
          <td>
Zemlak, Daniel and Leannon<br><span class="badge badge-ghost badge-sm">Desktop Support Technician</span>          </td>
          <td>Purple</td>
          <th>
<button class="btn btn-ghost btn-xs">details</button>          </th>
        </tr>
        <tr>
          <th>
<label>              <input type="checkbox" class="checkbox">
</label>          </th>
          <td>
            <div class="flex items-center gap-3">
              <div class="avatar">
                <div class="mask mask-squircle h-12 w-12">
<img src="https://img.daisyui.com/images/profile/demo/3@94.webp" alt="Avatar Tailwind CSS Component">                </div>
              </div>
              <div>
                <div class="font-bold">Brice Swyre</div>
                <div class="text-sm opacity-50">China</div>
              </div>
            </div>
          </td>
          <td>
Carroll Group<br><span class="badge badge-ghost badge-sm">Tax Accountant</span>          </td>
          <td>Red</td>
          <th>
<button class="btn btn-ghost btn-xs">details</button>          </th>
        </tr>
        <tr>
          <th>
<label>              <input type="checkbox" class="checkbox">
</label>          </th>
          <td>
            <div class="flex items-center gap-3">
              <div class="avatar">
                <div class="mask mask-squircle h-12 w-12">
<img src="https://img.daisyui.com/images/profile/demo/4@94.webp" alt="Avatar Tailwind CSS Component">                </div>
              </div>
              <div>
                <div class="font-bold">Marjy Ferencz</div>
                <div class="text-sm opacity-50">Russia</div>
              </div>
            </div>
          </td>
          <td>
Rowe-Schoen<br><span class="badge badge-ghost badge-sm">Office Assistant I</span>          </td>
          <td>Crimson</td>
          <th>
<button class="btn btn-ghost btn-xs">details</button>          </th>
        </tr>
        <tr>
          <th>
<label>              <input type="checkbox" class="checkbox">
</label>          </th>
          <td>
            <div class="flex items-center gap-3">
              <div class="avatar">
                <div class="mask mask-squircle h-12 w-12">
<img src="https://img.daisyui.com/images/profile/demo/5@94.webp" alt="Avatar Tailwind CSS Component">                </div>
              </div>
              <div>
                <div class="font-bold">Yancy Tear</div>
                <div class="text-sm opacity-50">Brazil</div>
              </div>
            </div>
          </td>
          <td>
Wyman-Ledner<br><span class="badge badge-ghost badge-sm">Community Outreach Specialist</span>          </td>
          <td>Indigo</td>
          <th>
<button class="btn btn-ghost btn-xs">details</button>          </th>
        </tr>
      </tbody>
      <tfoot>
        <tr>
          <th></th>
          <th>Name</th>
          <th>Job</th>
          <th>Favorite Color</th>
          <th></th>
        </tr>
      </tfoot>
    </table>
  </div>
</div>
test_func = test_table_visual_elements_fasthtml_examples
app, rt = create_test_app(theme=DaisyUITheme.LIGHT)

@rt
def index():
    return create_test_page(test_func.__doc__.title().replace('.', ''), test_func())
server = start_test_server(app)
display(HTMX())
server.stop()

source

test_table_sizes_fasthtml_examples

 test_table_sizes_fasthtml_examples ()

Test table xs size from daisyUI v5 documentation.

Exported source
def test_table_sizes_fasthtml_examples():
    """Test table xs size from daisyUI v5 documentation."""
    from fasthtml.common import Div, Table, Thead, Tbody, Tr, Th, Td, Tfoot
    from cjm_fasthtml_tailwind.utilities.layout import overflow
    from cjm_fasthtml_tailwind.core.base import combine_classes
    
    # Table xs (extra small)
    xs_table = Div(
        Table(
            Thead(
                Tr(
                    Th(),
                    Th("Name"),
                    Th("Job"),
                    Th("company"),
                    Th("location"),
                    Th("Last Login"),
                    Th("Favorite Color")
                )
            ),
            Tbody(
                Tr(
                    Th("1"),
                    Td("Cy Ganderton"),
                    Td("Quality Control Specialist"),
                    Td("Littel, Schaden and Vandervort"),
                    Td("Canada"),
                    Td("12/16/2020"),
                    Td("Blue")
                ),
                Tr(
                    Th("2"),
                    Td("Hart Hagerty"),
                    Td("Desktop Support Technician"),
                    Td("Zemlak, Daniel and Leannon"),
                    Td("United States"),
                    Td("12/5/2020"),
                    Td("Purple")
                ),
                Tr(
                    Th("3"),
                    Td("Brice Swyre"),
                    Td("Tax Accountant"),
                    Td("Carroll Group"),
                    Td("China"),
                    Td("8/15/2020"),
                    Td("Red")
                ),
                Tr(
                    Th("4"),
                    Td("Marjy Ferencz"),
                    Td("Office Assistant I"),
                    Td("Rowe-Schoen"),
                    Td("Russia"),
                    Td("3/25/2021"),
                    Td("Crimson")
                ),
                Tr(
                    Th("5"),
                    Td("Yancy Tear"),
                    Td("Community Outreach Specialist"),
                    Td("Wyman-Ledner"),
                    Td("Brazil"),
                    Td("5/22/2020"),
                    Td("Indigo")
                ),
                Tr(
                    Th("6"),
                    Td("Irma Vasilik"),
                    Td("Editor"),
                    Td("Wiza, Bins and Emard"),
                    Td("Venezuela"),
                    Td("12/8/2020"),
                    Td("Purple")
                ),
                Tr(
                    Th("7"),
                    Td("Meghann Durtnal"),
                    Td("Staff Accountant IV"),
                    Td("Schuster-Schimmel"),
                    Td("Philippines"),
                    Td("2/17/2021"),
                    Td("Yellow")
                ),
                Tr(
                    Th("8"),
                    Td("Sammy Seston"),
                    Td("Accountant I"),
                    Td("O'Hara, Welch and Keebler"),
                    Td("Indonesia"),
                    Td("5/23/2020"),
                    Td("Crimson")
                ),
                Tr(
                    Th("9"),
                    Td("Lesya Tinham"),
                    Td("Safety Technician IV"),
                    Td("Turner-Kuhlman"),
                    Td("Philippines"),
                    Td("2/21/2021"),
                    Td("Maroon")
                ),
                Tr(
                    Th("10"),
                    Td("Zaneta Tewkesbury"),
                    Td("VP Marketing"),
                    Td("Sauer LLC"),
                    Td("Chad"),
                    Td("6/23/2020"),
                    Td("Green")
                ),
                Tr(
                    Th("11"),
                    Td("Andy Tipple"),
                    Td("Librarian"),
                    Td("Hilpert Group"),
                    Td("Poland"),
                    Td("7/9/2020"),
                    Td("Indigo")
                ),
                Tr(
                    Th("12"),
                    Td("Sophi Biles"),
                    Td("Recruiting Manager"),
                    Td("Gutmann Inc"),
                    Td("Indonesia"),
                    Td("2/12/2021"),
                    Td("Maroon")
                ),
                Tr(
                    Th("13"),
                    Td("Florida Garces"),
                    Td("Web Developer IV"),
                    Td("Gaylord, Pacocha and Baumbach"),
                    Td("Poland"),
                    Td("5/31/2020"),
                    Td("Purple")
                ),
                Tr(
                    Th("14"),
                    Td("Maribeth Popping"),
                    Td("Analyst Programmer"),
                    Td("Deckow-Pouros"),
                    Td("Portugal"),
                    Td("4/27/2021"),
                    Td("Aquamarine")
                ),
                Tr(
                    Th("15"),
                    Td("Moritz Dryburgh"),
                    Td("Dental Hygienist"),
                    Td("Schiller, Cole and Hackett"),
                    Td("Sri Lanka"),
                    Td("8/8/2020"),
                    Td("Crimson")
                ),
                Tr(
                    Th("16"),
                    Td("Reid Semiras"),
                    Td("Teacher"),
                    Td("Sporer, Sipes and Rogahn"),
                    Td("Poland"),
                    Td("7/30/2020"),
                    Td("Green")
                ),
                Tr(
                    Th("17"),
                    Td("Alec Lethby"),
                    Td("Teacher"),
                    Td("Reichel, Glover and Hamill"),
                    Td("China"),
                    Td("2/28/2021"),
                    Td("Khaki")
                ),
                Tr(
                    Th("18"),
                    Td("Aland Wilber"),
                    Td("Quality Control Specialist"),
                    Td("Kshlerin, Rogahn and Swaniawski"),
                    Td("Czech Republic"),
                    Td("9/29/2020"),
                    Td("Purple")
                ),
                Tr(
                    Th("19"),
                    Td("Teddie Duerden"),
                    Td("Staff Accountant III"),
                    Td("Pouros, Ullrich and Windler"),
                    Td("France"),
                    Td("10/27/2020"),
                    Td("Aquamarine")
                ),
                Tr(
                    Th("20"),
                    Td("Lorelei Blackstone"),
                    Td("Data Coordinator"),
                    Td("Witting, Kutch and Greenfelder"),
                    Td("Kazakhstan"),
                    Td("6/3/2020"),
                    Td("Red")
                )
            ),
            Tfoot(
                Tr(
                    Th(),
                    Th("Name"),
                    Th("Job"),
                    Th("company"),
                    Th("location"),
                    Th("Last Login"),
                    Th("Favorite Color")
                )
            ),
            cls=combine_classes(table, table_sizes.xs)
        ),
        cls=combine_classes(overflow.x.auto)
    )
    
    # Verify table structure
    assert "overflow-x-auto" in xs_table.attrs['class']
    assert xs_table.children[0].tag == "table"
    assert "table" in xs_table.children[0].attrs['class']
    assert "table-xs" in xs_table.children[0].attrs['class']
    
    # Verify thead
    thead = xs_table.children[0].children[0]
    assert thead.tag == "thead"
    assert thead.children[0].tag == "tr"
    assert len(thead.children[0].children) == 7  # 7 columns
    assert thead.children[0].children[3].children[0] == "company"  # lowercase as in docs
    assert thead.children[0].children[4].children[0] == "location"  # lowercase as in docs
    
    # Verify tbody
    tbody = xs_table.children[0].children[1]
    assert tbody.tag == "tbody"
    assert len(tbody.children) == 20  # 20 rows
    
    # Verify first row
    first_row = tbody.children[0]
    assert first_row.tag == "tr"
    assert first_row.children[0].tag == "th"
    assert first_row.children[0].children[0] == "1"
    assert first_row.children[1].tag == "td"
    assert first_row.children[1].children[0] == "Cy Ganderton"
    assert first_row.children[2].children[0] == "Quality Control Specialist"
    assert first_row.children[3].children[0] == "Littel, Schaden and Vandervort"
    assert first_row.children[4].children[0] == "Canada"
    assert first_row.children[5].children[0] == "12/16/2020"
    assert first_row.children[6].children[0] == "Blue"
    
    # Verify last row
    last_row = tbody.children[19]
    assert last_row.tag == "tr"
    assert last_row.children[0].tag == "th"
    assert last_row.children[0].children[0] == "20"
    assert last_row.children[1].children[0] == "Lorelei Blackstone"
    assert last_row.children[2].children[0] == "Data Coordinator"
    assert last_row.children[3].children[0] == "Witting, Kutch and Greenfelder"
    assert last_row.children[4].children[0] == "Kazakhstan"
    assert last_row.children[5].children[0] == "6/3/2020"
    assert last_row.children[6].children[0] == "Red"
    
    # Verify tfoot
    tfoot = xs_table.children[0].children[2]
    assert tfoot.tag == "tfoot"
    assert tfoot.children[0].tag == "tr"
    assert len(tfoot.children[0].children) == 7  # 7 columns
    assert tfoot.children[0].children[1].children[0] == "Name"
    assert tfoot.children[0].children[2].children[0] == "Job"
    assert tfoot.children[0].children[3].children[0] == "company"  # lowercase as in docs
    assert tfoot.children[0].children[4].children[0] == "location"  # lowercase as in docs
    
    # Return the example in a Div
    return Div(xs_table)

# Run the tests
test_table_sizes_fasthtml_examples()
<div>
  <div class="overflow-x-auto">
    <table class="table table-xs">
      <thead>
        <tr>
          <th></th>
          <th>Name</th>
          <th>Job</th>
          <th>company</th>
          <th>location</th>
          <th>Last Login</th>
          <th>Favorite Color</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <th>1</th>
          <td>Cy Ganderton</td>
          <td>Quality Control Specialist</td>
          <td>Littel, Schaden and Vandervort</td>
          <td>Canada</td>
          <td>12/16/2020</td>
          <td>Blue</td>
        </tr>
        <tr>
          <th>2</th>
          <td>Hart Hagerty</td>
          <td>Desktop Support Technician</td>
          <td>Zemlak, Daniel and Leannon</td>
          <td>United States</td>
          <td>12/5/2020</td>
          <td>Purple</td>
        </tr>
        <tr>
          <th>3</th>
          <td>Brice Swyre</td>
          <td>Tax Accountant</td>
          <td>Carroll Group</td>
          <td>China</td>
          <td>8/15/2020</td>
          <td>Red</td>
        </tr>
        <tr>
          <th>4</th>
          <td>Marjy Ferencz</td>
          <td>Office Assistant I</td>
          <td>Rowe-Schoen</td>
          <td>Russia</td>
          <td>3/25/2021</td>
          <td>Crimson</td>
        </tr>
        <tr>
          <th>5</th>
          <td>Yancy Tear</td>
          <td>Community Outreach Specialist</td>
          <td>Wyman-Ledner</td>
          <td>Brazil</td>
          <td>5/22/2020</td>
          <td>Indigo</td>
        </tr>
        <tr>
          <th>6</th>
          <td>Irma Vasilik</td>
          <td>Editor</td>
          <td>Wiza, Bins and Emard</td>
          <td>Venezuela</td>
          <td>12/8/2020</td>
          <td>Purple</td>
        </tr>
        <tr>
          <th>7</th>
          <td>Meghann Durtnal</td>
          <td>Staff Accountant IV</td>
          <td>Schuster-Schimmel</td>
          <td>Philippines</td>
          <td>2/17/2021</td>
          <td>Yellow</td>
        </tr>
        <tr>
          <th>8</th>
          <td>Sammy Seston</td>
          <td>Accountant I</td>
          <td>O'Hara, Welch and Keebler</td>
          <td>Indonesia</td>
          <td>5/23/2020</td>
          <td>Crimson</td>
        </tr>
        <tr>
          <th>9</th>
          <td>Lesya Tinham</td>
          <td>Safety Technician IV</td>
          <td>Turner-Kuhlman</td>
          <td>Philippines</td>
          <td>2/21/2021</td>
          <td>Maroon</td>
        </tr>
        <tr>
          <th>10</th>
          <td>Zaneta Tewkesbury</td>
          <td>VP Marketing</td>
          <td>Sauer LLC</td>
          <td>Chad</td>
          <td>6/23/2020</td>
          <td>Green</td>
        </tr>
        <tr>
          <th>11</th>
          <td>Andy Tipple</td>
          <td>Librarian</td>
          <td>Hilpert Group</td>
          <td>Poland</td>
          <td>7/9/2020</td>
          <td>Indigo</td>
        </tr>
        <tr>
          <th>12</th>
          <td>Sophi Biles</td>
          <td>Recruiting Manager</td>
          <td>Gutmann Inc</td>
          <td>Indonesia</td>
          <td>2/12/2021</td>
          <td>Maroon</td>
        </tr>
        <tr>
          <th>13</th>
          <td>Florida Garces</td>
          <td>Web Developer IV</td>
          <td>Gaylord, Pacocha and Baumbach</td>
          <td>Poland</td>
          <td>5/31/2020</td>
          <td>Purple</td>
        </tr>
        <tr>
          <th>14</th>
          <td>Maribeth Popping</td>
          <td>Analyst Programmer</td>
          <td>Deckow-Pouros</td>
          <td>Portugal</td>
          <td>4/27/2021</td>
          <td>Aquamarine</td>
        </tr>
        <tr>
          <th>15</th>
          <td>Moritz Dryburgh</td>
          <td>Dental Hygienist</td>
          <td>Schiller, Cole and Hackett</td>
          <td>Sri Lanka</td>
          <td>8/8/2020</td>
          <td>Crimson</td>
        </tr>
        <tr>
          <th>16</th>
          <td>Reid Semiras</td>
          <td>Teacher</td>
          <td>Sporer, Sipes and Rogahn</td>
          <td>Poland</td>
          <td>7/30/2020</td>
          <td>Green</td>
        </tr>
        <tr>
          <th>17</th>
          <td>Alec Lethby</td>
          <td>Teacher</td>
          <td>Reichel, Glover and Hamill</td>
          <td>China</td>
          <td>2/28/2021</td>
          <td>Khaki</td>
        </tr>
        <tr>
          <th>18</th>
          <td>Aland Wilber</td>
          <td>Quality Control Specialist</td>
          <td>Kshlerin, Rogahn and Swaniawski</td>
          <td>Czech Republic</td>
          <td>9/29/2020</td>
          <td>Purple</td>
        </tr>
        <tr>
          <th>19</th>
          <td>Teddie Duerden</td>
          <td>Staff Accountant III</td>
          <td>Pouros, Ullrich and Windler</td>
          <td>France</td>
          <td>10/27/2020</td>
          <td>Aquamarine</td>
        </tr>
        <tr>
          <th>20</th>
          <td>Lorelei Blackstone</td>
          <td>Data Coordinator</td>
          <td>Witting, Kutch and Greenfelder</td>
          <td>Kazakhstan</td>
          <td>6/3/2020</td>
          <td>Red</td>
        </tr>
      </tbody>
      <tfoot>
        <tr>
          <th></th>
          <th>Name</th>
          <th>Job</th>
          <th>company</th>
          <th>location</th>
          <th>Last Login</th>
          <th>Favorite Color</th>
        </tr>
      </tfoot>
    </table>
  </div>
</div>
test_func = test_table_sizes_fasthtml_examples
app, rt = create_test_app(theme=DaisyUITheme.LIGHT)

@rt
def index():
    return create_test_page(test_func.__doc__.title().replace('.', ''), test_func())
server = start_test_server(app)
display(HTMX())
server.stop()

source

test_table_pinned_fasthtml_examples

 test_table_pinned_fasthtml_examples ()

Test table with pinned rows and pinned rows+columns from daisyUI v5 documentation.

Exported source
def test_table_pinned_fasthtml_examples():
    """Test table with pinned rows and pinned rows+columns from daisyUI v5 documentation."""
    from fasthtml.common import Div, Table, Thead, Tbody, Tr, Th, Td, Tfoot
    from cjm_fasthtml_tailwind.utilities.layout import overflow
    from cjm_fasthtml_tailwind.utilities.sizing import h
    from cjm_fasthtml_tailwind.core.base import combine_classes
    from cjm_fasthtml_daisyui.utilities.semantic_colors import bg_dui
    
    # Table with pinned rows
    pinned_rows_table = Div(
        Table(
            Thead(
                Tr(
                    Th("A")
                )
            ),
            Tbody(
                Tr(Td("Ant-Man")),
                Tr(Td("Aquaman")),
                Tr(Td("Asterix")),
                Tr(Td("The Atom")),
                Tr(Td("The Avengers"))
            ),
            Thead(
                Tr(
                    Th("B")
                )
            ),
            Tbody(
                Tr(Td("Batgirl")),
                Tr(Td("Batman")),
                Tr(Td("Batwoman")),
                Tr(Td("Black Canary")),
                Tr(Td("Black Panther"))
            ),
            Thead(
                Tr(
                    Th("C")
                )
            ),
            Tbody(
                Tr(Td("Captain America")),
                Tr(Td("Captain Marvel")),
                Tr(Td("Catwoman")),
                Tr(Td("Conan the Barbarian"))
            ),
            Thead(
                Tr(
                    Th("D")
                )
            ),
            Tbody(
                Tr(Td("Daredevil")),
                Tr(Td("The Defenders")),
                Tr(Td("Doc Savage")),
                Tr(Td("Doctor Strange"))
            ),
            Thead(
                Tr(
                    Th("E")
                )
            ),
            Tbody(
                Tr(Td("Elektra"))
            ),
            Thead(
                Tr(
                    Th("F")
                )
            ),
            Tbody(
                Tr(Td("Fantastic Four"))
            ),
            Thead(
                Tr(
                    Th("G")
                )
            ),
            Tbody(
                Tr(Td("Ghost Rider")),
                Tr(Td("Green Arrow")),
                Tr(Td("Green Lantern")),
                Tr(Td("Guardians of the Galaxy"))
            ),
            Thead(
                Tr(
                    Th("H")
                )
            ),
            Tbody(
                Tr(Td("Hawkeye")),
                Tr(Td("Hellboy")),
                Tr(Td("Incredible Hulk"))
            ),
            Thead(
                Tr(
                    Th("I")
                )
            ),
            Tbody(
                Tr(Td("Iron Fist")),
                Tr(Td("Iron Man"))
            ),
            Thead(
                Tr(
                    Th("M")
                )
            ),
            Tbody(
                Tr(Td("Marvelman"))
            ),
            Thead(
                Tr(
                    Th("R")
                )
            ),
            Tbody(
                Tr(Td("Robin")),
                Tr(Td("The Rocketeer"))
            ),
            Thead(
                Tr(
                    Th("S")
                )
            ),
            Tbody(
                Tr(Td("The Shadow")),
                Tr(Td("Spider-Man")),
                Tr(Td("Sub-Mariner")),
                Tr(Td("Supergirl")),
                Tr(Td("Superman"))
            ),
            Thead(
                Tr(
                    Th("T")
                )
            ),
            Tbody(
                Tr(Td("Teenage Mutant Ninja Turtles")),
                Tr(Td("Thor"))
            ),
            Thead(
                Tr(
                    Th("W")
                )
            ),
            Tbody(
                Tr(Td("The Wasp")),
                Tr(Td("Watchmen")),
                Tr(Td("Wolverine")),
                Tr(Td("Wonder Woman"))
            ),
            Thead(
                Tr(
                    Th("X")
                )
            ),
            Tbody(
                Tr(Td("X-Men"))
            ),
            Thead(
                Tr(
                    Th("Z")
                )
            ),
            Tbody(
                Tr(Td("Zatanna")),
                Tr(Td("Zatara"))
            ),
            cls=combine_classes(table, table_modifiers.pin_rows, bg_dui.base_200)
        ),
        cls=combine_classes(h._96, overflow.x.auto)
    )
    
    # Verify table structure
    assert "h-96" in pinned_rows_table.attrs['class']
    assert "overflow-x-auto" in pinned_rows_table.attrs['class']
    assert pinned_rows_table.children[0].tag == "table"
    assert "table" in pinned_rows_table.children[0].attrs['class']
    assert "table-pin-rows" in pinned_rows_table.children[0].attrs['class']
    assert "bg-base-200" in pinned_rows_table.children[0].attrs['class']
    
    # Verify alternating thead/tbody structure
    table_elem = pinned_rows_table.children[0]
    # First group - A
    assert table_elem.children[0].tag == "thead"
    assert table_elem.children[0].children[0].children[0].children[0] == "A"
    assert table_elem.children[1].tag == "tbody"
    assert table_elem.children[1].children[0].children[0].children[0] == "Ant-Man"
    assert table_elem.children[1].children[1].children[0].children[0] == "Aquaman"
    # Second group - B
    assert table_elem.children[2].tag == "thead"
    assert table_elem.children[2].children[0].children[0].children[0] == "B"
    assert table_elem.children[3].tag == "tbody"
    assert table_elem.children[3].children[0].children[0].children[0] == "Batgirl"
    # Last group - Z
    assert table_elem.children[-2].tag == "thead"
    assert table_elem.children[-2].children[0].children[0].children[0] == "Z"
    assert table_elem.children[-1].tag == "tbody"
    assert table_elem.children[-1].children[0].children[0].children[0] == "Zatanna"
    assert table_elem.children[-1].children[1].children[0].children[0] == "Zatara"
    
    # Table with pinned rows and columns
    pinned_both_table = Div(
        Table(
            Thead(
                Tr(
                    Th(),
                    Td("Name"),
                    Td("Job"),
                    Td("company"),
                    Td("location"),
                    Td("Last Login"),
                    Td("Favorite Color"),
                    Th()
                )
            ),
            Tbody(
                Tr(
                    Th("1"),
                    Td("Cy Ganderton"),
                    Td("Quality Control Specialist"),
                    Td("Littel, Schaden and Vandervort"),
                    Td("Canada"),
                    Td("12/16/2020"),
                    Td("Blue"),
                    Th("1")
                ),
                Tr(
                    Th("2"),
                    Td("Hart Hagerty"),
                    Td("Desktop Support Technician"),
                    Td("Zemlak, Daniel and Leannon"),
                    Td("United States"),
                    Td("12/5/2020"),
                    Td("Purple"),
                    Th("2")
                ),
                Tr(
                    Th("3"),
                    Td("Brice Swyre"),
                    Td("Tax Accountant"),
                    Td("Carroll Group"),
                    Td("China"),
                    Td("8/15/2020"),
                    Td("Red"),
                    Th("3")
                ),
                Tr(
                    Th("4"),
                    Td("Marjy Ferencz"),
                    Td("Office Assistant I"),
                    Td("Rowe-Schoen"),
                    Td("Russia"),
                    Td("3/25/2021"),
                    Td("Crimson"),
                    Th("4")
                ),
                Tr(
                    Th("5"),
                    Td("Yancy Tear"),
                    Td("Community Outreach Specialist"),
                    Td("Wyman-Ledner"),
                    Td("Brazil"),
                    Td("5/22/2020"),
                    Td("Indigo"),
                    Th("5")
                ),
                Tr(
                    Th("6"),
                    Td("Irma Vasilik"),
                    Td("Editor"),
                    Td("Wiza, Bins and Emard"),
                    Td("Venezuela"),
                    Td("12/8/2020"),
                    Td("Purple"),
                    Th("6")
                ),
                Tr(
                    Th("7"),
                    Td("Meghann Durtnal"),
                    Td("Staff Accountant IV"),
                    Td("Schuster-Schimmel"),
                    Td("Philippines"),
                    Td("2/17/2021"),
                    Td("Yellow"),
                    Th("7")
                ),
                Tr(
                    Th("8"),
                    Td("Sammy Seston"),
                    Td("Accountant I"),
                    Td("O'Hara, Welch and Keebler"),
                    Td("Indonesia"),
                    Td("5/23/2020"),
                    Td("Crimson"),
                    Th("8")
                ),
                Tr(
                    Th("9"),
                    Td("Lesya Tinham"),
                    Td("Safety Technician IV"),
                    Td("Turner-Kuhlman"),
                    Td("Philippines"),
                    Td("2/21/2021"),
                    Td("Maroon"),
                    Th("9")
                ),
                Tr(
                    Th("10"),
                    Td("Zaneta Tewkesbury"),
                    Td("VP Marketing"),
                    Td("Sauer LLC"),
                    Td("Chad"),
                    Td("6/23/2020"),
                    Td("Green"),
                    Th("10")
                ),
                Tr(
                    Th("11"),
                    Td("Andy Tipple"),
                    Td("Librarian"),
                    Td("Hilpert Group"),
                    Td("Poland"),
                    Td("7/9/2020"),
                    Td("Indigo"),
                    Th("11")
                ),
                Tr(
                    Th("12"),
                    Td("Sophi Biles"),
                    Td("Recruiting Manager"),
                    Td("Gutmann Inc"),
                    Td("Indonesia"),
                    Td("2/12/2021"),
                    Td("Maroon"),
                    Th("12")
                ),
                Tr(
                    Th("13"),
                    Td("Florida Garces"),
                    Td("Web Developer IV"),
                    Td("Gaylord, Pacocha and Baumbach"),
                    Td("Poland"),
                    Td("5/31/2020"),
                    Td("Purple"),
                    Th("13")
                ),
                Tr(
                    Th("14"),
                    Td("Maribeth Popping"),
                    Td("Analyst Programmer"),
                    Td("Deckow-Pouros"),
                    Td("Portugal"),
                    Td("4/27/2021"),
                    Td("Aquamarine"),
                    Th("14")
                ),
                Tr(
                    Th("15"),
                    Td("Moritz Dryburgh"),
                    Td("Dental Hygienist"),
                    Td("Schiller, Cole and Hackett"),
                    Td("Sri Lanka"),
                    Td("8/8/2020"),
                    Td("Crimson"),
                    Th("15")
                ),
                Tr(
                    Th("16"),
                    Td("Reid Semiras"),
                    Td("Teacher"),
                    Td("Sporer, Sipes and Rogahn"),
                    Td("Poland"),
                    Td("7/30/2020"),
                    Td("Green"),
                    Th("16")
                ),
                Tr(
                    Th("17"),
                    Td("Alec Lethby"),
                    Td("Teacher"),
                    Td("Reichel, Glover and Hamill"),
                    Td("China"),
                    Td("2/28/2021"),
                    Td("Khaki"),
                    Th("17")
                ),
                Tr(
                    Th("18"),
                    Td("Aland Wilber"),
                    Td("Quality Control Specialist"),
                    Td("Kshlerin, Rogahn and Swaniawski"),
                    Td("Czech Republic"),
                    Td("9/29/2020"),
                    Td("Purple"),
                    Th("18")
                ),
                Tr(
                    Th("19"),
                    Td("Teddie Duerden"),
                    Td("Staff Accountant III"),
                    Td("Pouros, Ullrich and Windler"),
                    Td("France"),
                    Td("10/27/2020"),
                    Td("Aquamarine"),
                    Th("19")
                ),
                Tr(
                    Th("20"),
                    Td("Lorelei Blackstone"),
                    Td("Data Coordinator"),
                    Td("Witting, Kutch and Greenfelder"),
                    Td("Kazakhstan"),
                    Td("6/3/2020"),
                    Td("Red"),
                    Th("20")
                )
            ),
            Tfoot(
                Tr(
                    Th(),
                    Td("Name"),
                    Td("Job"),
                    Td("company"),
                    Td("location"),
                    Td("Last Login"),
                    Td("Favorite Color"),
                    Th()
                )
            ),
            cls=combine_classes(table, table_sizes.xs, table_modifiers.pin_rows, table_modifiers.pin_cols)
        ),
        cls=combine_classes(overflow.x.auto)
    )
    
    # Verify table structure
    assert "overflow-x-auto" in pinned_both_table.attrs['class']
    assert pinned_both_table.children[0].tag == "table"
    assert "table" in pinned_both_table.children[0].attrs['class']
    assert "table-xs" in pinned_both_table.children[0].attrs['class']
    assert "table-pin-rows" in pinned_both_table.children[0].attrs['class']
    assert "table-pin-cols" in pinned_both_table.children[0].attrs['class']
    
    # Verify thead uses td instead of th for column headers (except first and last)
    thead = pinned_both_table.children[0].children[0]
    assert thead.tag == "thead"
    tr = thead.children[0]
    assert tr.children[0].tag == "th"  # First column is th
    assert tr.children[0].children == ()  # Empty
    assert tr.children[1].tag == "td"  # Column headers are td
    assert tr.children[1].children[0] == "Name"
    assert tr.children[2].tag == "td"
    assert tr.children[2].children[0] == "Job"
    assert tr.children[-1].tag == "th"  # Last column is th
    assert tr.children[-1].children == ()  # Empty
    
    # Verify tbody rows have th at both ends
    tbody = pinned_both_table.children[0].children[1]
    assert tbody.tag == "tbody"
    first_row = tbody.children[0]
    assert first_row.children[0].tag == "th"
    assert first_row.children[0].children[0] == "1"
    assert first_row.children[1].tag == "td"
    assert first_row.children[1].children[0] == "Cy Ganderton"
    assert first_row.children[-1].tag == "th"
    assert first_row.children[-1].children[0] == "1"  # Same number on both sides
    
    # Verify last row
    last_row = tbody.children[19]
    assert last_row.children[0].tag == "th"
    assert last_row.children[0].children[0] == "20"
    assert last_row.children[1].children[0] == "Lorelei Blackstone"
    assert last_row.children[-1].tag == "th"
    assert last_row.children[-1].children[0] == "20"  # Same number on both sides
    
    # Verify tfoot structure
    tfoot = pinned_both_table.children[0].children[2]
    assert tfoot.tag == "tfoot"
    tfoot_tr = tfoot.children[0]
    assert tfoot_tr.children[0].tag == "th"  # First column is th
    assert tfoot_tr.children[1].tag == "td"  # Column footers are td
    assert tfoot_tr.children[1].children[0] == "Name"
    assert tfoot_tr.children[-1].tag == "th"  # Last column is th
    
    # Return all examples in a Div
    return Div(
        pinned_rows_table,
        pinned_both_table
    )

# Run the tests
test_table_pinned_fasthtml_examples()
<div>
  <div class="h-96 overflow-x-auto">
    <table class="table table-pin-rows bg-base-200">
      <thead>
        <tr>
          <th>A</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Ant-Man</td>
        </tr>
        <tr>
          <td>Aquaman</td>
        </tr>
        <tr>
          <td>Asterix</td>
        </tr>
        <tr>
          <td>The Atom</td>
        </tr>
        <tr>
          <td>The Avengers</td>
        </tr>
      </tbody>
      <thead>
        <tr>
          <th>B</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Batgirl</td>
        </tr>
        <tr>
          <td>Batman</td>
        </tr>
        <tr>
          <td>Batwoman</td>
        </tr>
        <tr>
          <td>Black Canary</td>
        </tr>
        <tr>
          <td>Black Panther</td>
        </tr>
      </tbody>
      <thead>
        <tr>
          <th>C</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Captain America</td>
        </tr>
        <tr>
          <td>Captain Marvel</td>
        </tr>
        <tr>
          <td>Catwoman</td>
        </tr>
        <tr>
          <td>Conan the Barbarian</td>
        </tr>
      </tbody>
      <thead>
        <tr>
          <th>D</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Daredevil</td>
        </tr>
        <tr>
          <td>The Defenders</td>
        </tr>
        <tr>
          <td>Doc Savage</td>
        </tr>
        <tr>
          <td>Doctor Strange</td>
        </tr>
      </tbody>
      <thead>
        <tr>
          <th>E</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Elektra</td>
        </tr>
      </tbody>
      <thead>
        <tr>
          <th>F</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Fantastic Four</td>
        </tr>
      </tbody>
      <thead>
        <tr>
          <th>G</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Ghost Rider</td>
        </tr>
        <tr>
          <td>Green Arrow</td>
        </tr>
        <tr>
          <td>Green Lantern</td>
        </tr>
        <tr>
          <td>Guardians of the Galaxy</td>
        </tr>
      </tbody>
      <thead>
        <tr>
          <th>H</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Hawkeye</td>
        </tr>
        <tr>
          <td>Hellboy</td>
        </tr>
        <tr>
          <td>Incredible Hulk</td>
        </tr>
      </tbody>
      <thead>
        <tr>
          <th>I</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Iron Fist</td>
        </tr>
        <tr>
          <td>Iron Man</td>
        </tr>
      </tbody>
      <thead>
        <tr>
          <th>M</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Marvelman</td>
        </tr>
      </tbody>
      <thead>
        <tr>
          <th>R</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Robin</td>
        </tr>
        <tr>
          <td>The Rocketeer</td>
        </tr>
      </tbody>
      <thead>
        <tr>
          <th>S</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>The Shadow</td>
        </tr>
        <tr>
          <td>Spider-Man</td>
        </tr>
        <tr>
          <td>Sub-Mariner</td>
        </tr>
        <tr>
          <td>Supergirl</td>
        </tr>
        <tr>
          <td>Superman</td>
        </tr>
      </tbody>
      <thead>
        <tr>
          <th>T</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Teenage Mutant Ninja Turtles</td>
        </tr>
        <tr>
          <td>Thor</td>
        </tr>
      </tbody>
      <thead>
        <tr>
          <th>W</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>The Wasp</td>
        </tr>
        <tr>
          <td>Watchmen</td>
        </tr>
        <tr>
          <td>Wolverine</td>
        </tr>
        <tr>
          <td>Wonder Woman</td>
        </tr>
      </tbody>
      <thead>
        <tr>
          <th>X</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>X-Men</td>
        </tr>
      </tbody>
      <thead>
        <tr>
          <th>Z</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Zatanna</td>
        </tr>
        <tr>
          <td>Zatara</td>
        </tr>
      </tbody>
    </table>
  </div>
  <div class="overflow-x-auto">
    <table class="table table-xs table-pin-rows table-pin-cols">
      <thead>
        <tr>
          <th></th>
          <td>Name</td>
          <td>Job</td>
          <td>company</td>
          <td>location</td>
          <td>Last Login</td>
          <td>Favorite Color</td>
          <th></th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <th>1</th>
          <td>Cy Ganderton</td>
          <td>Quality Control Specialist</td>
          <td>Littel, Schaden and Vandervort</td>
          <td>Canada</td>
          <td>12/16/2020</td>
          <td>Blue</td>
          <th>1</th>
        </tr>
        <tr>
          <th>2</th>
          <td>Hart Hagerty</td>
          <td>Desktop Support Technician</td>
          <td>Zemlak, Daniel and Leannon</td>
          <td>United States</td>
          <td>12/5/2020</td>
          <td>Purple</td>
          <th>2</th>
        </tr>
        <tr>
          <th>3</th>
          <td>Brice Swyre</td>
          <td>Tax Accountant</td>
          <td>Carroll Group</td>
          <td>China</td>
          <td>8/15/2020</td>
          <td>Red</td>
          <th>3</th>
        </tr>
        <tr>
          <th>4</th>
          <td>Marjy Ferencz</td>
          <td>Office Assistant I</td>
          <td>Rowe-Schoen</td>
          <td>Russia</td>
          <td>3/25/2021</td>
          <td>Crimson</td>
          <th>4</th>
        </tr>
        <tr>
          <th>5</th>
          <td>Yancy Tear</td>
          <td>Community Outreach Specialist</td>
          <td>Wyman-Ledner</td>
          <td>Brazil</td>
          <td>5/22/2020</td>
          <td>Indigo</td>
          <th>5</th>
        </tr>
        <tr>
          <th>6</th>
          <td>Irma Vasilik</td>
          <td>Editor</td>
          <td>Wiza, Bins and Emard</td>
          <td>Venezuela</td>
          <td>12/8/2020</td>
          <td>Purple</td>
          <th>6</th>
        </tr>
        <tr>
          <th>7</th>
          <td>Meghann Durtnal</td>
          <td>Staff Accountant IV</td>
          <td>Schuster-Schimmel</td>
          <td>Philippines</td>
          <td>2/17/2021</td>
          <td>Yellow</td>
          <th>7</th>
        </tr>
        <tr>
          <th>8</th>
          <td>Sammy Seston</td>
          <td>Accountant I</td>
          <td>O'Hara, Welch and Keebler</td>
          <td>Indonesia</td>
          <td>5/23/2020</td>
          <td>Crimson</td>
          <th>8</th>
        </tr>
        <tr>
          <th>9</th>
          <td>Lesya Tinham</td>
          <td>Safety Technician IV</td>
          <td>Turner-Kuhlman</td>
          <td>Philippines</td>
          <td>2/21/2021</td>
          <td>Maroon</td>
          <th>9</th>
        </tr>
        <tr>
          <th>10</th>
          <td>Zaneta Tewkesbury</td>
          <td>VP Marketing</td>
          <td>Sauer LLC</td>
          <td>Chad</td>
          <td>6/23/2020</td>
          <td>Green</td>
          <th>10</th>
        </tr>
        <tr>
          <th>11</th>
          <td>Andy Tipple</td>
          <td>Librarian</td>
          <td>Hilpert Group</td>
          <td>Poland</td>
          <td>7/9/2020</td>
          <td>Indigo</td>
          <th>11</th>
        </tr>
        <tr>
          <th>12</th>
          <td>Sophi Biles</td>
          <td>Recruiting Manager</td>
          <td>Gutmann Inc</td>
          <td>Indonesia</td>
          <td>2/12/2021</td>
          <td>Maroon</td>
          <th>12</th>
        </tr>
        <tr>
          <th>13</th>
          <td>Florida Garces</td>
          <td>Web Developer IV</td>
          <td>Gaylord, Pacocha and Baumbach</td>
          <td>Poland</td>
          <td>5/31/2020</td>
          <td>Purple</td>
          <th>13</th>
        </tr>
        <tr>
          <th>14</th>
          <td>Maribeth Popping</td>
          <td>Analyst Programmer</td>
          <td>Deckow-Pouros</td>
          <td>Portugal</td>
          <td>4/27/2021</td>
          <td>Aquamarine</td>
          <th>14</th>
        </tr>
        <tr>
          <th>15</th>
          <td>Moritz Dryburgh</td>
          <td>Dental Hygienist</td>
          <td>Schiller, Cole and Hackett</td>
          <td>Sri Lanka</td>
          <td>8/8/2020</td>
          <td>Crimson</td>
          <th>15</th>
        </tr>
        <tr>
          <th>16</th>
          <td>Reid Semiras</td>
          <td>Teacher</td>
          <td>Sporer, Sipes and Rogahn</td>
          <td>Poland</td>
          <td>7/30/2020</td>
          <td>Green</td>
          <th>16</th>
        </tr>
        <tr>
          <th>17</th>
          <td>Alec Lethby</td>
          <td>Teacher</td>
          <td>Reichel, Glover and Hamill</td>
          <td>China</td>
          <td>2/28/2021</td>
          <td>Khaki</td>
          <th>17</th>
        </tr>
        <tr>
          <th>18</th>
          <td>Aland Wilber</td>
          <td>Quality Control Specialist</td>
          <td>Kshlerin, Rogahn and Swaniawski</td>
          <td>Czech Republic</td>
          <td>9/29/2020</td>
          <td>Purple</td>
          <th>18</th>
        </tr>
        <tr>
          <th>19</th>
          <td>Teddie Duerden</td>
          <td>Staff Accountant III</td>
          <td>Pouros, Ullrich and Windler</td>
          <td>France</td>
          <td>10/27/2020</td>
          <td>Aquamarine</td>
          <th>19</th>
        </tr>
        <tr>
          <th>20</th>
          <td>Lorelei Blackstone</td>
          <td>Data Coordinator</td>
          <td>Witting, Kutch and Greenfelder</td>
          <td>Kazakhstan</td>
          <td>6/3/2020</td>
          <td>Red</td>
          <th>20</th>
        </tr>
      </tbody>
      <tfoot>
        <tr>
          <th></th>
          <td>Name</td>
          <td>Job</td>
          <td>company</td>
          <td>location</td>
          <td>Last Login</td>
          <td>Favorite Color</td>
          <th></th>
        </tr>
      </tfoot>
    </table>
  </div>
</div>
test_func = test_table_pinned_fasthtml_examples
app, rt = create_test_app(theme=DaisyUITheme.LIGHT)

@rt
def index():
    return create_test_page(test_func.__doc__.title().replace('.', ''), test_func())
server = start_test_server(app)
display(HTMX())
server.stop()