Exported source
table = SingleValueFactory("table", "Table component for displaying data in rows and columns") # Table componentThe base table component:
Table modifier utilities:
Table size variants:
test_table_basic_examples ()
Test basic table utilities.
test_table_modifiers_examples ()
Test table modifier utilities.
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()test_table_sizes_examples ()
Test table size variants.
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()test_table_basic_fasthtml_examples ()
Test basic table and table with border and background from daisyUI v5 documentation.
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_table_style_fasthtml_examples ()
Test table with active row, hover row, and zebra stripes from daisyUI v5 documentation.
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_table_visual_elements_fasthtml_examples ()
Test table with visual elements from daisyUI v5 documentation.
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_table_sizes_fasthtml_examples ()
Test table xs size from daisyUI v5 documentation.
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_table_pinned_fasthtml_examples ()
Test table with pinned rows and pinned rows+columns from daisyUI v5 documentation.
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>