Combobox
Example:
Code example:
from htmy import ComponentType
from htmui.basecoat.combobox import combobox, option
def example() -> ComponentType:
return combobox(
option("Apple", value="apple"),
option("Banana", value="banana", selected=True),
option("Orange", value="orange", force=True),
option("Strawberry", value="strawberry", keywords="fields forever"),
option("Not an option", value="not-an-option", disabled=True),
id="my-select-with-search",
button_class="w-40",
)
Component implementation:
For more details, see the BasecoatUI documentation.
from htmy import ComponentType, PropertyValue, SafeStr, html, join_classes
__version__ = "0.1.0"
__framework__ = "BasecoatUI"
__framework_version__ = "0.3"
__framework_url__ = "https://basecoatui.com/components/combobox/"
js = SafeStr(
'<script src="https://cdn.jsdelivr.net/npm/basecoat-css@0.3/dist/js/select.min.js" defer></script>'
)
"""Combobox uses the same JavaScript as the `select` component."""
dropdown_icon = SafeStr(
'<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" '
'stroke="currentColor" class="size-5"><path stroke-linecap="round" stroke-linejoin="round" '
'd="M8.25 15 12 18.75 15.75 15m-7.5-6L12 5.25 15.75 9" /></svg>'
)
"""`chevron-up-down` icon from https://heroicons.com/."""
def combobox(
*children: ComponentType,
id: str,
button_class: str = "btn-outline",
button_label: str = "",
button_icon: ComponentType = dropdown_icon,
class_: str | None = None,
search_placeholder: str = "Search...",
) -> ComponentType:
button_id = f"{id}-button"
listbox_id = f"{id}-listbox"
return html.div(
html.button(
html.span(button_label),
button_icon,
class_=join_classes("btn-outline justify-between", button_class),
id=button_id,
type="button",
aria_haspopup="listbox",
aria_expanded="false",
aria_controls=listbox_id,
),
html.div(
html.header(
html.input_(
type="text",
value="",
placeholder=search_placeholder,
autocomplete="off",
autocorrect="off",
spellcheck="false",
aria_autocomplete="list",
role="combobox",
aria_expanded="false",
aria_controls=listbox_id,
aria_labelledby=button_id,
)
),
html.div(
*children,
role="listbox",
id=listbox_id,
aria_orientation="vertical",
aria_labelledby=button_id,
),
id=f"{id}-popover",
data_popover="",
aria_hidden="true",
),
html.input_(type="hidden", name=f"select-{id}-value", value=""),
class_=join_classes("select", class_),
id=id,
)
def option(
*children: ComponentType,
value: str,
disabled: bool = False,
force: bool = False,
keywords: str | None = None,
selected: bool = False,
**kwargs: PropertyValue,
) -> ComponentType:
"""Search option component for `select_with_search`."""
kwargs["role"] = "option"
kwargs["data-value"] = value
if disabled:
kwargs["aria-disabled"] = "true"
if force:
kwargs["data-force"] = "true"
if keywords:
kwargs["data-keywords"] = keywords
if selected:
kwargs["aria-selected"] = "true"
return html.div(*children, **kwargs)