dropdown

Dropdown can open a menu or any other element when the button is clicked.

Base Dropdown

Exported source
dropdown = SingleValueFactory("dropdown", "Dropdown container component") # Dropdown container
dropdown_content = SingleValueFactory("dropdown-content", "Content part of dropdown") # Dropdown content

test_dropdown_basic_examples


def test_dropdown_basic_examples(
    
):

Test basic dropdown utilities.

Exported source
def test_dropdown_basic_examples():
    """Test basic dropdown utilities."""
    assert str(dropdown) == "dropdown"
    assert str(dropdown_content) == "dropdown-content"
    
    # With modifiers
    assert str(dropdown.hover) == "hover:dropdown"
    assert str(dropdown_content.md) == "md:dropdown-content"

# Run the tests
test_dropdown_basic_examples()

test_dropdown_placement_examples


def test_dropdown_placement_examples(
    
):

Test dropdown placement options.

Exported source
def test_dropdown_placement_examples():
    """Test dropdown placement options."""
    # Horizontal alignment
    assert str(dropdown_placement.start) == "dropdown-start"
    assert str(dropdown_placement.center) == "dropdown-center"
    assert str(dropdown_placement.end) == "dropdown-end"
    
    # Vertical position
    assert str(dropdown_placement.top) == "dropdown-top"
    assert str(dropdown_placement.bottom) == "dropdown-bottom"
    assert str(dropdown_placement.left) == "dropdown-left"
    assert str(dropdown_placement.right) == "dropdown-right"

# Run the tests
test_dropdown_placement_examples()

test_dropdown_modifiers_examples


def test_dropdown_modifiers_examples(
    
):

Test dropdown modifier utilities.

Exported source
def test_dropdown_modifiers_examples():
    """Test dropdown modifier utilities."""
    assert str(dropdown_modifiers.hover) == "dropdown-hover"
    assert str(dropdown_modifiers.open) == "dropdown-open"

# Run the tests
test_dropdown_modifiers_examples()

test_dropdown_basic_fasthtml_examples


def test_dropdown_basic_fasthtml_examples(
    
):

Test basic dropdown implementations including details/summary and popover API.

Exported source
def test_dropdown_basic_fasthtml_examples():
    """Test basic dropdown implementations including details/summary and popover API."""
    from fasthtml.common import Details, Summary, Ul, Li, A, Div, Button
    from cjm_fasthtml_tailwind.core.base import combine_classes
    from cjm_fasthtml_tailwind.utilities.spacing import m, p
    from cjm_fasthtml_tailwind.utilities.layout import z
    from cjm_fasthtml_tailwind.utilities.sizing import w
    from cjm_fasthtml_tailwind.utilities.effects import shadow
    from cjm_fasthtml_daisyui.utilities.semantic_colors import bg_dui
    from cjm_fasthtml_daisyui.utilities.border_radius import border_radius
    from cjm_fasthtml_daisyui.components.actions.button import btn
    from cjm_fasthtml_daisyui.components.navigation.menu import menu
    
    # Dropdown using details and summary
    dropdown_details = Details(
        Summary("open or close", cls=combine_classes(btn, m._1)),
        Ul(
            Li(A("Item 1")),
            Li(A("Item 2")),
            cls=combine_classes(
                menu,
                dropdown_content,
                bg_dui.base_100,
                border_radius.box,
                z._1,
                w._52,
                p._2,
                shadow.sm
            )
        ),
        cls=str(dropdown)
    )
    assert dropdown_details.tag == "details"
    assert "dropdown" in dropdown_details.attrs['class']
    assert "btn" in dropdown_details.children[0].attrs['class']
    assert "dropdown-content" in dropdown_details.children[1].attrs['class']
    
    # Dropdown using popover API and anchor positioning
    popover_button = Button(
        "Button",
        cls=str(btn),
        popovertarget="popover-1",
        style="anchor-name:--anchor-1"
    )
    popover_menu = Ul(
        Li(A("Item 1")),
        Li(A("Item 2")),
        cls=combine_classes(dropdown, menu, w._52, border_radius.box, bg_dui.base_100, shadow.sm),
        popover=True,
        id="popover-1",
        style="position-anchor:--anchor-1"
    )
    assert popover_button.attrs['popovertarget'] == "popover-1"
    assert popover_menu.attrs['popover'] == True
    assert popover_menu.attrs['id'] == "popover-1"
    
    # Basic dropdown menu
    basic_dropdown = Div(
        Div("Click", tabindex="0", role="button", cls=combine_classes(btn, m._1)),
        Ul(
            Li(A("Item 1")),
            Li(A("Item 2")),
            tabindex="0",
            cls=combine_classes(
                dropdown_content,
                menu,
                bg_dui.base_100,
                border_radius.box,
                z._1,
                w._52,
                p._2,
                shadow.sm
            )
        ),
        cls=str(dropdown)
    )
    assert "dropdown" in basic_dropdown.attrs['class']
    assert basic_dropdown.children[0].attrs['role'] == "button"
    assert basic_dropdown.children[0].attrs['tabindex'] == "0"
    
    # Return all elements in a Div
    return Div(
        dropdown_details,
        popover_button,
        popover_menu,
        basic_dropdown
    )

# Run the tests
test_dropdown_basic_fasthtml_examples()
test_func = test_dropdown_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()

test_dropdown_placement_fasthtml_examples


def test_dropdown_placement_fasthtml_examples(
    
):

Test dropdown placement variations for all positions.

Exported source
def test_dropdown_placement_fasthtml_examples():
    """Test dropdown placement variations for all positions."""
    from fasthtml.common import Div, Ul, Li, A
    from cjm_fasthtml_tailwind.core.base import combine_classes
    from cjm_fasthtml_tailwind.utilities.spacing import m, p
    from cjm_fasthtml_tailwind.utilities.layout import z
    from cjm_fasthtml_tailwind.utilities.sizing import w
    from cjm_fasthtml_tailwind.utilities.effects import shadow
    from cjm_fasthtml_daisyui.utilities.semantic_colors import bg_dui
    from cjm_fasthtml_daisyui.utilities.border_radius import border_radius
    from cjm_fasthtml_daisyui.components.actions.button import btn
    from cjm_fasthtml_daisyui.components.navigation.menu import menu
    
    # Helper function to create dropdown content
    def create_dropdown_content():
        return Ul(
            Li(A("Item 1")),
            Li(A("Item 2")),
            tabindex="0",
            cls=combine_classes(
                dropdown_content,
                menu,
                bg_dui.base_100,
                border_radius.box,
                z._1,
                w._52,
                p._2,
                shadow.sm
            )
        )
    
    # Dropdown start (aligns to start of button horizontally)
    dropdown_start = Div(
        Div("Click ⬇️", tabindex="0", role="button", cls=combine_classes(btn, m._1)),
        create_dropdown_content(),
        cls=combine_classes(dropdown, dropdown_placement.start)
    )
    assert "dropdown-start" in dropdown_start.attrs['class']
    
    # Dropdown end (aligns to end of button horizontally)
    dropdown_end = Div(
        Div("Click ⬇️", tabindex="0", role="button", cls=combine_classes(btn, m._1)),
        create_dropdown_content(),
        cls=combine_classes(dropdown, dropdown_placement.end)
    )
    assert "dropdown-end" in dropdown_end.attrs['class']
    
    # Dropdown center (aligns to center of button horizontally)
    dropdown_center = Div(
        Div("Click ⬇️", tabindex="0", role="button", cls=combine_classes(btn, m._1)),
        create_dropdown_content(),
        cls=combine_classes(dropdown, dropdown_placement.center)
    )
    assert "dropdown-center" in dropdown_center.attrs['class']
    
    # Dropdown top
    dropdown_top = Div(
        Div("Click ⬆️", tabindex="0", role="button", cls=combine_classes(btn, m._1)),
        create_dropdown_content(),
        cls=combine_classes(dropdown, dropdown_placement.top)
    )
    assert "dropdown-top" in dropdown_top.attrs['class']
    
    # Dropdown top center
    dropdown_top_center = Div(
        Div("Click ⬆️", tabindex="0", role="button", cls=combine_classes(btn, m._1)),
        create_dropdown_content(),
        cls=combine_classes(dropdown, dropdown_placement.top, dropdown_placement.center)
    )
    assert "dropdown-top" in dropdown_top_center.attrs['class']
    assert "dropdown-center" in dropdown_top_center.attrs['class']
    
    # Dropdown top end
    dropdown_top_end = Div(
        Div("Click ⬆️", tabindex="0", role="button", cls=combine_classes(btn, m._1)),
        create_dropdown_content(),
        cls=combine_classes(dropdown, dropdown_placement.top, dropdown_placement.end)
    )
    assert "dropdown-top" in dropdown_top_end.attrs['class']
    assert "dropdown-end" in dropdown_top_end.attrs['class']
    
    # Dropdown bottom (default)
    dropdown_bottom = Div(
        Div("Click ⬇️", tabindex="0", role="button", cls=combine_classes(btn, m._1)),
        create_dropdown_content(),
        cls=combine_classes(dropdown, dropdown_placement.bottom)
    )
    assert "dropdown-bottom" in dropdown_bottom.attrs['class']
    
    # Dropdown bottom center
    dropdown_bottom_center = Div(
        Div("Click ⬇️", tabindex="0", role="button", cls=combine_classes(btn, m._1)),
        create_dropdown_content(),
        cls=combine_classes(dropdown, dropdown_placement.bottom, dropdown_placement.center)
    )
    assert "dropdown-bottom" in dropdown_bottom_center.attrs['class']
    assert "dropdown-center" in dropdown_bottom_center.attrs['class']
    
    # Dropdown bottom end
    dropdown_bottom_end = Div(
        Div("Click ⬇️", tabindex="0", role="button", cls=combine_classes(btn, m._1)),
        create_dropdown_content(),
        cls=combine_classes(dropdown, dropdown_placement.bottom, dropdown_placement.end)
    )
    assert "dropdown-bottom" in dropdown_bottom_end.attrs['class']
    assert "dropdown-end" in dropdown_bottom_end.attrs['class']
    
    # Dropdown left
    dropdown_left = Div(
        Div("Click ⬅️", tabindex="0", role="button", cls=combine_classes(btn, m._1)),
        create_dropdown_content(),
        cls=combine_classes(dropdown, dropdown_placement.left)
    )
    assert "dropdown-left" in dropdown_left.attrs['class']
    
    # Dropdown left center
    dropdown_left_center = Div(
        Div("Click ⬅️", tabindex="0", role="button", cls=combine_classes(btn, m._1)),
        create_dropdown_content(),
        cls=combine_classes(dropdown, dropdown_placement.left, dropdown_placement.center)
    )
    assert "dropdown-left" in dropdown_left_center.attrs['class']
    assert "dropdown-center" in dropdown_left_center.attrs['class']
    
    # Dropdown left end
    dropdown_left_end = Div(
        Div("Click ⬅️", tabindex="0", role="button", cls=combine_classes(btn, m._1)),
        create_dropdown_content(),
        cls=combine_classes(dropdown, dropdown_placement.left, dropdown_placement.end)
    )
    assert "dropdown-left" in dropdown_left_end.attrs['class']
    assert "dropdown-end" in dropdown_left_end.attrs['class']
    
    # Dropdown right
    dropdown_right = Div(
        Div("Click ➡️", tabindex="0", role="button", cls=combine_classes(btn, m._1)),
        create_dropdown_content(),
        cls=combine_classes(dropdown, dropdown_placement.right)
    )
    assert "dropdown-right" in dropdown_right.attrs['class']
    
    # Dropdown right center
    dropdown_right_center = Div(
        Div("Click ➡️", tabindex="0", role="button", cls=combine_classes(btn, m._1)),
        create_dropdown_content(),
        cls=combine_classes(dropdown, dropdown_placement.right, dropdown_placement.center)
    )
    assert "dropdown-right" in dropdown_right_center.attrs['class']
    assert "dropdown-center" in dropdown_right_center.attrs['class']
    
    # Dropdown right end
    dropdown_right_end = Div(
        Div("Click ➡️", tabindex="0", role="button", cls=combine_classes(btn, m._1)),
        create_dropdown_content(),
        cls=combine_classes(dropdown, dropdown_placement.right, dropdown_placement.end)
    )
    assert "dropdown-right" in dropdown_right_end.attrs['class']
    assert "dropdown-end" in dropdown_right_end.attrs['class']
    
    # Return all elements in a Div
    return Div(
        dropdown_start,
        dropdown_end,
        dropdown_center,
        dropdown_top,
        dropdown_top_center,
        dropdown_top_end,
        dropdown_bottom,
        dropdown_bottom_center,
        dropdown_bottom_end,
        dropdown_left,
        dropdown_left_center,
        dropdown_left_end,
        dropdown_right,
        dropdown_right_center,
        dropdown_right_end
    )

# Run the tests
test_dropdown_placement_fasthtml_examples()
test_func = test_dropdown_placement_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()

test_dropdown_hover_and_state_fasthtml_examples


def test_dropdown_hover_and_state_fasthtml_examples(
    
):

Test dropdown hover behavior and force open state.

Exported source
def test_dropdown_hover_and_state_fasthtml_examples():
    """Test dropdown hover behavior and force open state."""
    from fasthtml.common import Div, Ul, Li, A
    from cjm_fasthtml_tailwind.utilities.spacing import m, p
    from cjm_fasthtml_tailwind.utilities.layout import z
    from cjm_fasthtml_tailwind.utilities.sizing import w
    from cjm_fasthtml_tailwind.utilities.effects import shadow
    from cjm_fasthtml_daisyui.utilities.semantic_colors import bg_dui
    from cjm_fasthtml_daisyui.utilities.border_radius import border_radius
    from cjm_fasthtml_daisyui.components.actions.button import btn
    from cjm_fasthtml_daisyui.components.navigation.menu import menu
    
    # Dropdown on hover
    dropdown_hover = Div(
        Div("Hover", tabindex="0", role="button", cls=combine_classes(btn, m._1)),
        Ul(
            Li(A("Item 1")),
            Li(A("Item 2")),
            tabindex="0",
            cls=combine_classes(
                dropdown_content,
                menu,
                bg_dui.base_100,
                border_radius.box,
                z._1,
                w._52,
                p._2,
                shadow.sm
            )
        ),
        cls=combine_classes(dropdown, dropdown_modifiers.hover)
    )
    assert "dropdown" in dropdown_hover.attrs['class']
    assert "dropdown-hover" in dropdown_hover.attrs['class']
    
    # Force open dropdown
    dropdown_open = Div(
        Div("Button", tabindex="0", role="button", cls=combine_classes(btn, m._1)),
        Ul(
            Li(A("Item 1")),
            Li(A("Item 2")),
            tabindex="0",
            cls=combine_classes(
                dropdown_content,
                menu,
                bg_dui.base_100,
                border_radius.box,
                z._1,
                w._52,
                p._2,
                shadow.sm
            )
        ),
        cls=combine_classes(dropdown, dropdown_modifiers.open)
    )
    assert "dropdown" in dropdown_open.attrs['class']
    assert "dropdown-open" in dropdown_open.attrs['class']
    
    # Return all elements in a Div
    return Div(
        dropdown_hover,
        dropdown_open
    )

# Run the tests
test_dropdown_hover_and_state_fasthtml_examples()
test_func = test_dropdown_hover_and_state_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()

test_dropdown_content_variations_fasthtml_examples


def test_dropdown_content_variations_fasthtml_examples(
    
):

Test dropdown with different content types including cards and navbar integration.

Exported source
def test_dropdown_content_variations_fasthtml_examples():
    """Test dropdown with different content types including cards and navbar integration."""
    from fasthtml.common import Div, Ul, Li, A, P, H2, Nav
    from fasthtml.svg import Svg, Path
    from cjm_fasthtml_tailwind.utilities.spacing import m, p, ps
    from cjm_fasthtml_tailwind.utilities.layout import z, display_tw
    from cjm_fasthtml_tailwind.utilities.sizing import w, h
    from cjm_fasthtml_tailwind.utilities.effects import shadow
    from cjm_fasthtml_tailwind.utilities.typography import font_size, font_weight, font_family, text_color
    from cjm_fasthtml_tailwind.utilities.flexbox_and_grid import flex, items, justify, flex_display
    from cjm_fasthtml_tailwind.utilities.svg import stroke
    from cjm_fasthtml_daisyui.utilities.semantic_colors import bg_dui, text_dui
    from cjm_fasthtml_daisyui.utilities.border_radius import border_radius
    from cjm_fasthtml_daisyui.components.actions.button import btn, btn_styles, btn_modifiers, btn_sizes
    from cjm_fasthtml_daisyui.components.navigation.menu import menu
    from cjm_fasthtml_daisyui.components.navigation.navbar import navbar
    from cjm_fasthtml_daisyui.components.data_display.card import card, card_body, card_title, card_sizes
    
    # Card as dropdown content
    dropdown_card = Div(
        Div("Click", tabindex="0", role="button", cls=combine_classes(btn, m._1)),
        Div(
            Div(
                P("This is a card. You can use any element as a dropdown."),
                cls=str(card_body)
            ),
            tabindex="0",
            cls=combine_classes(
                dropdown_content,
                card,
                card_sizes.sm,
                bg_dui.base_100,
                z._1,
                w._64,
                shadow.md
            )
        ),
        cls=str(dropdown)
    )
    assert "dropdown" in dropdown_card.attrs['class']
    assert "card" in dropdown_card.children[1].attrs['class']
    assert "dropdown-content" in dropdown_card.children[1].attrs['class']
    
    # Dropdown in navbar
    navbar_dropdown = Div(
        Div(
            A("daisyUI", cls=combine_classes(font_size.lg, font_weight.bold)),
            cls=str(ps._4)
        ),
        Div(
            Div(
                A("Button", cls=combine_classes(btn, btn_styles.ghost, border_radius.field)),
                Div(
                    Div(
                        "Dropdown",
                        tabindex="0",
                        role="button",
                        cls=combine_classes(btn, btn_styles.ghost, border_radius.field)
                    ),
                    Ul(
                        Li(A("Item 1")),
                        Li(A("Item 2")),
                        tabindex="0",
                        cls=combine_classes(
                            menu,
                            dropdown_content,
                            bg_dui.base_200,
                            border_radius.box,
                            z._1,
                            m.t._4,
                            w._52,
                            p._2,
                            shadow.sm
                        )
                    ),
                    cls=combine_classes(dropdown, dropdown_placement.end)
                ),
                cls=combine_classes(flex_display, items.stretch)
            ),
            cls=combine_classes(flex_display, flex.grow, justify.end, p.x._2)
        ),
        cls=combine_classes(navbar, bg_dui.base_200)
    )
    assert "navbar" in navbar_dropdown.attrs['class']
    dropdown_in_navbar = navbar_dropdown.children[1].children[0].children[1]
    assert "dropdown" in dropdown_in_navbar.attrs['class']
    assert "dropdown-end" in dropdown_in_navbar.attrs['class']
    
    # Helper dropdown with info icon
    info_icon = Svg(
        Path(
            stroke_linecap="round",
            stroke_linejoin="round",
            stroke_width="2",
            d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
        ),
        tabindex="0",
        xmlns="http://www.w3.org/2000/svg",
        fill="none",
        viewBox="0 0 24 24",
        cls=combine_classes(h._4, w._4, stroke.current)
    )
    
    helper_dropdown = [
        "A normal text and a helper dropdown",
        Div(
            Div(
                info_icon,
                tabindex="0",
                role="button",
                cls=combine_classes(
                    btn,
                    btn_modifiers.circle,
                    btn_styles.ghost,
                    btn_sizes.xs,
                    text_dui.info
                )
            ),
            Div(
                Div(
                    H2("You needed more info?", cls=str(card_title)),
                    P("Here is a description!"),
                    tabindex="0",
                    cls=str(card_body)
                ),
                tabindex="0",
                cls=combine_classes(
                    card,
                    card_sizes.sm,
                    dropdown_content,
                    bg_dui.base_100,
                    border_radius.box,
                    z._1,
                    w._64,
                    shadow.sm
                )
            ),
            cls=combine_classes(dropdown, dropdown_placement.end)
        )
    ]
    helper_dropdown_div = helper_dropdown[1]
    assert "dropdown" in helper_dropdown_div.attrs['class']
    assert "dropdown-end" in helper_dropdown_div.attrs['class']
    assert "btn-circle" in helper_dropdown_div.children[0].attrs['class']
    assert "btn-ghost" in helper_dropdown_div.children[0].attrs['class']
    assert "btn-xs" in helper_dropdown_div.children[0].attrs['class']
    
    # Return all elements in a Div
    return Div(
        dropdown_card,
        navbar_dropdown,
        helper_dropdown[0],  # The text
        helper_dropdown_div  # The dropdown
    )

# Run the tests
test_dropdown_content_variations_fasthtml_examples()
A normal text and a helper dropdown
test_func = test_dropdown_content_variations_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()