swap

Swap allows you to toggle the visibility of two elements using a checkbox or a class name.

Base Swap Components

Exported source
swap = SingleValueFactory("swap", "Swap container component") # Swap container
swap_on = SingleValueFactory("swap-on", "The child element that should be visible when checkbox is checked or when swap is active") # Swap on state
swap_off = SingleValueFactory("swap-off", "The child element that should be visible when checkbox is not checked or when swap is not active") # Swap off state
swap_indeterminate = SingleValueFactory("swap-indeterminate", "The child element that should be visible when checkbox is indeterminate") # Swap indeterminate state

Swap Styles and State

Exported source
swap_styles = SimpleFactory(
    {
        "rotate": "swap-rotate",
        "flip": "swap-flip",
        "active": "swap-active"
    },
    "Swap animation styles and active state"
) # Swap styles

Swap Test Examples


source

test_swap_basic_examples

 test_swap_basic_examples ()

Test basic swap utilities.

Exported source
def test_swap_basic_examples():
    """Test basic swap utilities."""
    assert str(swap) == "swap"
    assert str(swap_on) == "swap-on"
    assert str(swap_off) == "swap-off"
    assert str(swap_indeterminate) == "swap-indeterminate"
    
    # With modifiers
    assert str(swap.hover) == "hover:swap"
    assert str(swap_on.md) == "md:swap-on"

# Run the tests
test_swap_basic_examples()

source

test_swap_styles_examples

 test_swap_styles_examples ()

Test swap style utilities.

Exported source
def test_swap_styles_examples():
    """Test swap style utilities."""
    assert str(swap_styles.rotate) == "swap-rotate"
    assert str(swap_styles.flip) == "swap-flip"
    assert str(swap_styles.active) == "swap-active"

# Run the tests
test_swap_styles_examples()

source

test_swap_basic_fasthtml_examples

 test_swap_basic_fasthtml_examples ()

Test basic swap examples including text and icon swaps.

Exported source
def test_swap_basic_fasthtml_examples():
    """Test basic swap examples including text and icon swaps."""
    from fasthtml.common import Label, Input, Div
    from fasthtml.svg import Svg, Path
    from cjm_fasthtml_tailwind.utilities.svg import fill
    
    # Basic text swap
    text_swap = Label(
        Input(type="checkbox"),
        Div("ON", cls=str(swap_on)),
        Div("OFF", cls=str(swap_off)),
        cls=str(swap)
    )
    assert text_swap.tag == "label"
    assert "swap" in text_swap.attrs['class']
    assert text_swap.children[0].tag == "input"
    assert text_swap.children[0].attrs['type'] == "checkbox"
    assert "swap-on" in text_swap.children[1].attrs['class']
    assert "swap-off" in text_swap.children[2].attrs['class']
    
    # Swap volume icons
    volume_on_svg = Svg(
        Path(
            d="M14,3.23V5.29C16.89,6.15 19,8.83 19,12C19,15.17 16.89,17.84 14,18.7V20.77C18,19.86 21,16.28 21,12C21,7.72 18,4.14 14,3.23M16.5,12C16.5,10.23 15.5,8.71 14,7.97V16C15.5,15.29 16.5,13.76 16.5,12M3,9V15H7L12,20V4L7,9H3Z"
        ),
        cls=combine_classes(swap_on, fill.current),
        xmlns="http://www.w3.org/2000/svg",
        width="48",
        height="48",
        viewBox="0 0 24 24"
    )
    
    volume_off_svg = Svg(
        Path(
            d="M3,9H7L12,4V20L7,15H3V9M16.59,12L14,9.41L15.41,8L18,10.59L20.59,8L22,9.41L19.41,12L22,14.59L20.59,16L18,13.41L15.41,16L14,14.59L16.59,12Z"
        ),
        cls=combine_classes(swap_off, fill.current),
        xmlns="http://www.w3.org/2000/svg",
        width="48",
        height="48",
        viewBox="0 0 24 24"
    )
    
    volume_swap = Label(
        Input(type="checkbox"),
        volume_on_svg,
        volume_off_svg,
        cls=str(swap)
    )
    assert len(volume_swap.children) == 3
    assert volume_swap.children[0].tag == "input"
    assert volume_swap.children[1].tag == "svg"
    assert volume_swap.children[2].tag == "svg"
    assert "swap-on" in volume_swap.children[1].attrs['class']
    assert "swap-off" in volume_swap.children[2].attrs['class']
    assert "fill-current" in volume_swap.children[1].attrs['class']
    assert "fill-current" in volume_swap.children[2].attrs['class']
    
    # Return all elements in a Div
    return Div(
        text_swap,
        volume_swap
    )

# Run the tests
test_swap_basic_fasthtml_examples()
<div>
<label class="swap">    <input type="checkbox">
    <div class="swap-on">ON</div>
    <div class="swap-off">OFF</div>
</label><label class="swap">    <input type="checkbox">
<svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" height="48" width="48" class="swap-on fill-current"><path d="M14,3.23V5.29C16.89,6.15 19,8.83 19,12C19,15.17 16.89,17.84 14,18.7V20.77C18,19.86 21,16.28 21,12C21,7.72 18,4.14 14,3.23M16.5,12C16.5,10.23 15.5,8.71 14,7.97V16C15.5,15.29 16.5,13.76 16.5,12M3,9V15H7L12,20V4L7,9H3Z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" height="48" width="48" class="swap-off fill-current"><path d="M3,9H7L12,4V20L7,15H3V9M16.59,12L14,9.41L15.41,8L18,10.59L20.59,8L22,9.41L19.41,12L22,14.59L20.59,16L18,13.41L15.41,16L14,14.59L16.59,12Z"></path></svg></label></div>
test_func = test_swap_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_swap_effects_fasthtml_examples

 test_swap_effects_fasthtml_examples ()

Test swap examples with rotate and flip effects.

Exported source
def test_swap_effects_fasthtml_examples():
    """Test swap examples with rotate and flip effects."""
    from fasthtml.common import Label, Input, Div
    from fasthtml.svg import Svg, Path
    from cjm_fasthtml_tailwind.utilities.svg import fill
    from cjm_fasthtml_tailwind.utilities.sizing import h, w
    from cjm_fasthtml_tailwind.utilities.typography import font_size, font_weight, font_family, text_color
    
    # Create sun icon SVG
    sun_icon = Svg(
        Path(
            d="M5.64,17l-.71.71a1,1,0,0,0,0,1.41,1,1,0,0,0,1.41,0l.71-.71A1,1,0,0,0,5.64,17ZM5,12a1,1,0,0,0-1-1H3a1,1,0,0,0,0,2H4A1,1,0,0,0,5,12Zm7-7a1,1,0,0,0,1-1V3a1,1,0,0,0-2,0V4A1,1,0,0,0,12,5ZM5.64,7.05a1,1,0,0,0,.7.29,1,1,0,0,0,.71-.29,1,1,0,0,0,0-1.41l-.71-.71A1,1,0,0,0,4.93,6.34Zm12,.29a1,1,0,0,0,.7-.29l.71-.71a1,1,0,1,0-1.41-1.41L17,5.64a1,1,0,0,0,0,1.41A1,1,0,0,0,17.66,7.34ZM21,11H20a1,1,0,0,0,0,2h1a1,1,0,0,0,0-2Zm-9,8a1,1,0,0,0-1,1v1a1,1,0,0,0,2,0V20A1,1,0,0,0,12,19ZM18.36,17A1,1,0,0,0,17,18.36l.71.71a1,1,0,0,0,1.41,0,1,1,0,0,0,0-1.41ZM12,6.5A5.5,5.5,0,1,0,17.5,12,5.51,5.51,0,0,0,12,6.5Zm0,9A3.5,3.5,0,1,1,15.5,12,3.5,3.5,0,0,1,12,15.5Z"
        ),
        cls=combine_classes(swap_on, h._10, w._10, fill.current),
        xmlns="http://www.w3.org/2000/svg",
        viewBox="0 0 24 24"
    )
    
    # Create moon icon SVG
    moon_icon = Svg(
        Path(
            d="M21.64,13a1,1,0,0,0-1.05-.14,8.05,8.05,0,0,1-3.37.73A8.15,8.15,0,0,1,9.08,5.49a8.59,8.59,0,0,1,.25-2A1,1,0,0,0,8,2.36,10.14,10.14,0,1,0,22,14.05,1,1,0,0,0,21.64,13Zm-9.5,6.69A8.14,8.14,0,0,1,7.08,5.22v.27A10.15,10.15,0,0,0,17.22,15.63a9.79,9.79,0,0,0,2.1-.22A8.11,8.11,0,0,1,12.14,19.73Z"
        ),
        cls=combine_classes(swap_off, h._10, w._10, fill.current),
        xmlns="http://www.w3.org/2000/svg",
        viewBox="0 0 24 24"
    )
    
    # Swap icons with rotate effect
    rotate_swap = Label(
        Input(type="checkbox"),
        sun_icon,
        moon_icon,
        cls=combine_classes(swap, swap_styles.rotate)
    )
    assert "swap" in rotate_swap.attrs['class']
    assert "swap-rotate" in rotate_swap.attrs['class']
    assert "h-10" in rotate_swap.children[1].attrs['class']
    assert "w-10" in rotate_swap.children[1].attrs['class']
    assert "swap-on" in rotate_swap.children[1].attrs['class']
    assert "swap-off" in rotate_swap.children[2].attrs['class']
    
    # Swap icons with flip effect
    flip_swap = Label(
        Input(type="checkbox"),
        Div("😈", cls=str(swap_on)),
        Div("😇", cls=str(swap_off)),
        cls=combine_classes(swap, swap_styles.flip, font_size._9xl)
    )
    assert "swap" in flip_swap.attrs['class']
    assert "swap-flip" in flip_swap.attrs['class']
    assert "text-9xl" in flip_swap.attrs['class']
    assert flip_swap.children[1].children[0] == "😈"
    assert flip_swap.children[2].children[0] == "😇"
    
    # Return all elements in a Div
    return Div(
        rotate_swap,
        flip_swap
    )

# Run the tests
test_swap_effects_fasthtml_examples()
<div>
<label class="swap swap-rotate">    <input type="checkbox">
<svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" class="swap-on h-10 w-10 fill-current"><path d="M5.64,17l-.71.71a1,1,0,0,0,0,1.41,1,1,0,0,0,1.41,0l.71-.71A1,1,0,0,0,5.64,17ZM5,12a1,1,0,0,0-1-1H3a1,1,0,0,0,0,2H4A1,1,0,0,0,5,12Zm7-7a1,1,0,0,0,1-1V3a1,1,0,0,0-2,0V4A1,1,0,0,0,12,5ZM5.64,7.05a1,1,0,0,0,.7.29,1,1,0,0,0,.71-.29,1,1,0,0,0,0-1.41l-.71-.71A1,1,0,0,0,4.93,6.34Zm12,.29a1,1,0,0,0,.7-.29l.71-.71a1,1,0,1,0-1.41-1.41L17,5.64a1,1,0,0,0,0,1.41A1,1,0,0,0,17.66,7.34ZM21,11H20a1,1,0,0,0,0,2h1a1,1,0,0,0,0-2Zm-9,8a1,1,0,0,0-1,1v1a1,1,0,0,0,2,0V20A1,1,0,0,0,12,19ZM18.36,17A1,1,0,0,0,17,18.36l.71.71a1,1,0,0,0,1.41,0,1,1,0,0,0,0-1.41ZM12,6.5A5.5,5.5,0,1,0,17.5,12,5.51,5.51,0,0,0,12,6.5Zm0,9A3.5,3.5,0,1,1,15.5,12,3.5,3.5,0,0,1,12,15.5Z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" class="swap-off h-10 w-10 fill-current"><path d="M21.64,13a1,1,0,0,0-1.05-.14,8.05,8.05,0,0,1-3.37.73A8.15,8.15,0,0,1,9.08,5.49a8.59,8.59,0,0,1,.25-2A1,1,0,0,0,8,2.36,10.14,10.14,0,1,0,22,14.05,1,1,0,0,0,21.64,13Zm-9.5,6.69A8.14,8.14,0,0,1,7.08,5.22v.27A10.15,10.15,0,0,0,17.22,15.63a9.79,9.79,0,0,0,2.1-.22A8.11,8.11,0,0,1,12.14,19.73Z"></path></svg></label><label class="swap swap-flip text-9xl">    <input type="checkbox">
    <div class="swap-on">😈</div>
    <div class="swap-off">😇</div>
</label></div>
test_func = test_swap_effects_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_swap_advanced_fasthtml_examples

 test_swap_advanced_fasthtml_examples ()

Test advanced swap examples including hamburger button and class-based activation.

Exported source
def test_swap_advanced_fasthtml_examples():
    """Test advanced swap examples including hamburger button and class-based activation."""
    from fasthtml.common import Label, Input, Div
    from fasthtml.svg import Svg, Path, Polygon
    from cjm_fasthtml_tailwind.utilities.svg import fill
    from cjm_fasthtml_tailwind.utilities.typography import font_size, font_weight, font_family, text_color
    from cjm_fasthtml_daisyui.components.actions.button import btn, btn_modifiers
    
    # Hamburger button
    hamburger_icon = Svg(
        Path(d="M64,384H448V341.33H64Zm0-106.67H448V234.67H64ZM64,128v42.67H448V128Z"),
        cls=combine_classes(swap_off, fill.current),
        xmlns="http://www.w3.org/2000/svg",
        width="32",
        height="32",
        viewBox="0 0 512 512"
    )
    
    close_icon = Svg(
        Polygon(
            points="400 145.49 366.51 112 256 222.51 145.49 112 112 145.49 222.51 256 112 366.51 145.49 400 256 289.49 366.51 400 400 366.51 289.49 256 400 145.49"
        ),
        cls=combine_classes(swap_on, fill.current),
        xmlns="http://www.w3.org/2000/svg",
        width="32",
        height="32",
        viewBox="0 0 512 512"
    )
    
    hamburger_button = Label(
        Input(type="checkbox"),
        hamburger_icon,
        close_icon,
        cls=combine_classes(btn, btn_modifiers.circle, swap, swap_styles.rotate)
    )
    assert "btn" in hamburger_button.attrs['class']
    assert "btn-circle" in hamburger_button.attrs['class']
    assert "swap" in hamburger_button.attrs['class']
    assert "swap-rotate" in hamburger_button.attrs['class']
    assert hamburger_button.children[1].tag == "svg"
    assert hamburger_button.children[2].tag == "svg"
    
    # Test class-based activation (without checkbox)
    # Inactive state
    class_swap_inactive = Label(
        Div("🥵", cls=str(swap_on)),
        Div("🥶", cls=str(swap_off)),
        cls=combine_classes(swap, font_size._6xl)
    )
    assert "swap" in class_swap_inactive.attrs['class']
    assert "text-6xl" in class_swap_inactive.attrs['class']
    assert len(class_swap_inactive.children) == 2  # No input element
    assert class_swap_inactive.children[0].children[0] == "🥵"
    assert class_swap_inactive.children[1].children[0] == "🥶"
    
    # Active state using class
    class_swap_active = Label(
        Div("🥳", cls=str(swap_on)),
        Div("😭", cls=str(swap_off)),
        cls=combine_classes(swap, swap_styles.active, font_size._6xl)
    )
    assert "swap" in class_swap_active.attrs['class']
    assert "swap-active" in class_swap_active.attrs['class']
    assert "text-6xl" in class_swap_active.attrs['class']
    assert class_swap_active.children[0].children[0] == "🥳"
    assert class_swap_active.children[1].children[0] == "😭"
    
    # Verify indeterminate state (from factory definition)
    indeterminate_swap = Label(
        Input(type="checkbox", indeterminate=True),
        Div("ON", cls=str(swap_on)),
        Div("OFF", cls=str(swap_off)),
        Div("INDETERMINATE", cls=str(swap_indeterminate)),
        cls=str(swap)
    )
    assert len(indeterminate_swap.children) == 4
    assert "swap-indeterminate" in indeterminate_swap.children[3].attrs['class']
    
    # Return all elements in a Div
    return Div(
        hamburger_button,
        class_swap_inactive,
        class_swap_active,
        indeterminate_swap
    )

# Run the tests
test_swap_advanced_fasthtml_examples()
<div>
<label class="btn btn-circle swap swap-rotate">    <input type="checkbox">
<svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 512 512" height="32" width="32" class="swap-off fill-current"><path d="M64,384H448V341.33H64Zm0-106.67H448V234.67H64ZM64,128v42.67H448V128Z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 512 512" height="32" width="32" class="swap-on fill-current"><polygon points="400 145.49 366.51 112 256 222.51 145.49 112 112 145.49 222.51 256 112 366.51 145.49 400 256 289.49 366.51 400 400 366.51 289.49 256 400 145.49"></polygon></svg></label><label class="swap text-6xl">    <div class="swap-on">🥵</div>
    <div class="swap-off">🥶</div>
</label><label class="swap swap-active text-6xl">    <div class="swap-on">🥳</div>
    <div class="swap-off">😭</div>
</label><label class="swap">    <input type="checkbox" indeterminate>
    <div class="swap-on">ON</div>
    <div class="swap-off">OFF</div>
    <div class="swap-indeterminate">INDETERMINATE</div>
</label></div>
test_func = test_swap_advanced_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()