Tabs
Example:
First panel
First panel content.
Second panel
Second panel content.
Code example:
from htmy import ComponentType, html
from htmui.basecoat.tabs import tab_button, tab_panel, tabs
def example() -> ComponentType:
panel_1_id = "example-panel-1"
button_1_id = f"{panel_1_id}-button"
panel_2_id = "example-panel-2"
button_2_id = f"{panel_2_id}-button"
return html.div(
tabs(
tab_panel(
html.div(
html.header(html.h2("First panel"), html.p("First panel content.")),
class_="card",
),
id=panel_1_id,
button_id=button_1_id,
selected=True,
class_="w-80",
),
tab_panel(
html.div(
html.header(html.h2("Second panel"), html.p("Second panel content.")),
class_="card",
),
id=panel_2_id,
button_id=button_2_id,
class_="w-80",
),
buttons=(
tab_button(
"First",
id=button_1_id,
panel_id=panel_1_id,
selected=True,
),
tab_button(
"Second",
id=button_2_id,
panel_id=panel_2_id,
),
),
)
)
Component implementation:
For more details, see the BasecoatUI documentation.
from typing import Literal, TypeAlias
from htmy import ComponentSequence, ComponentType, PropertyValue, SafeStr, html, join_classes
__version__ = "0.2.0"
__framework__ = "BasecoatUI"
__framework_version__ = "1"
__framework_url__ = "https://basecoatui.com/components/tabs/"
js = SafeStr(
'<script src="https://cdn.jsdelivr.net/npm/basecoat-css@1/dist/js/tabs.min.js" defer></script>'
)
Orientation: TypeAlias = Literal["horizontal", "vertical"]
TabsVariant: TypeAlias = Literal["line"]
def tab_button(
*children: ComponentType,
id: str,
panel_id: str,
selected: bool = False,
class_: str | None = None,
**kwargs: PropertyValue,
) -> ComponentType:
"""
Tab button.
Arguments:
*children: Button content.
id: Button ID.
panel_id: The ID of the controlled tab panel.
selected: Whether this tab is active.
class_: Extra CSS classes for the button.
**kwargs: Extra attributes for the button.
"""
return html.button(
*children,
type="button",
role="tab",
id=id,
aria_controls=panel_id,
aria_selected="true" if selected else "false",
tabindex="0" if selected else "-1",
class_=class_,
**kwargs,
)
def tab_panel(
*children: ComponentType,
id: str,
button_id: str,
selected: bool = False,
class_: str | None = None,
**kwargs: PropertyValue,
) -> ComponentType:
"""
Tab panel.
Arguments:
*children: Panel content.
id: Panel ID.
button_id: The ID of the button that controls this tab panel.
selected: Whether this panel is active.
class_: Extra CSS classes for the panel.
**kwargs: Extra attributes for the panel.
"""
if not selected:
kwargs["hidden"] = ""
return html.div(
*children,
role="tabpanel",
id=id,
aria_labelledby=button_id,
tabindex="-1",
aria_selected="true" if selected else "false",
class_=class_,
**kwargs,
)
def tabs(
*panels: ComponentType,
buttons: ComponentSequence,
orientation: Orientation = "horizontal",
variant: TabsVariant | None = None,
class_: str | None = None,
**kwargs: PropertyValue,
) -> ComponentType:
"""
Tabs root with a tablist and panels.
Arguments:
*panels: Tab panels.
buttons: Sequence of tab buttons.
orientation: Tablist orientation.
variant: Optional tablist style.
class_: Extra CSS classes for the root element.
**kwargs: Extra attributes for the root element.
"""
return html.div(
html.nav(*buttons, role="tablist", aria_orientation=orientation, data_variant=variant),
*panels,
class_=join_classes("tabs", class_),
**kwargs,
)