Skip to content

InputGroup

The InputGroup component extends form controls by adding text, buttons, or icons before or after inputs. Perfect for currency fields, search boxes, and any input that needs context or actions.

Goal

Master creating input groups with addons, understand Bootstrap input-group classes, and build enhanced form controls that provide better user context and functionality.


Quick Start

Live Preview
@
from faststrap import InputGroup, InputGroupText, Input

InputGroup(
    InputGroupText("@"),
    Input("username", placeholder="Username")
)

Visual Examples & Use Cases

1. Text Addons - Provide Context

Add text before or after inputs to clarify what users should enter.

Live Preview
$ .00
.com
https://
# Currency input
InputGroup(
    InputGroupText("$"),
    Input("amount", input_type="number", placeholder="0.00"),
    InputGroupText(".00")
)

# Domain input
InputGroup(
    Input("domain", placeholder="Your website"),
    InputGroupText(".com")
)

# URL input
InputGroup(
    InputGroupText("https://"),
    Input("url", placeholder="example.com")
)

2. Button Addons - Add Actions

Combine inputs with buttons for immediate actions.

Live Preview
from faststrap import InputGroup, Input, Button, Icon

# Search box
InputGroup(
    Input("search", placeholder="Search..."),
    Button(Icon("search"), " Search", variant="primary")
)

# Copy link
InputGroup(
    Button("Copy", variant="outline-secondary", 
           onclick="navigator.clipboard.writeText(this.nextElementSibling.value)"),
    Input("share_link", value="https://example.com/share/abc123", readonly=True)
)

3. Dropdown Addons - Multiple Options

Add dropdown menus to input groups for filtering or actions.

from faststrap import InputGroup, Input, Dropdown, DropdownItem

InputGroup(
    Dropdown(
        DropdownItem("All Categories", href="#"),
        DropdownItem("Electronics", href="#"),
        DropdownItem("Clothing", href="#"),
        DropdownItem("Books", href="#"),
        label="Category",
        variant="outline-secondary"
    ),
    Input("search", placeholder="Search products...")
)

4. Icon Addons - Visual Indicators

Use icons to indicate input purpose.

from faststrap import InputGroup, InputGroupText, Input, Icon

# Email input with icon
InputGroup(
    InputGroupText(Icon("envelope")),
    Input("email", input_type="email", placeholder="Email address")
)

# Password input with icon
InputGroup(
    InputGroupText(Icon("lock")),
    Input("password", input_type="password", placeholder="Password")
)

# Phone input with icon
InputGroup(
    InputGroupText(Icon("telephone")),
    Input("phone", input_type="tel", placeholder="Phone number")
)

5. Sizes - Match Your Design

Live Preview
@
@
@
# Large
InputGroup(
    InputGroupText("@"),
    Input("username", placeholder="Large"),
    size="lg"
)

# Default
InputGroup(
    InputGroupText("@"),
    Input("username", placeholder="Default")
)

# Small
InputGroup(
    InputGroupText("@"),
    Input("username", placeholder="Small"),
    size="sm"
)

Practical Functionality

Search Box with HTMX

from faststrap import InputGroup, Input, Button, Icon

InputGroup(
    Input(
        "search",
        placeholder="Search products...",
        hx_get="/search",
        hx_trigger="keyup changed delay:500ms",
        hx_target="#search-results"
    ),
    Button(
        Icon("search"),
        variant="primary",
        hx_get="/search",
        hx_include="[name='search']",
        hx_target="#search-results"
    )
)

Promo Code Input

from faststrap import InputGroup, Input, Button

InputGroup(
    Input("promo_code", placeholder="Enter promo code"),
    Button(
        "Apply",
        variant="success",
        hx_post="/apply-promo",
        hx_include="[name='promo_code']",
        hx_target="#cart-total",
        hx_swap="outerHTML"
    ),
    cls="mb-3"
)

File Upload with Button

from faststrap import InputGroup, Button

InputGroup(
    Input("file", input_type="file", cls="form-control"),
    Button(
        Icon("upload"), " Upload",
        variant="primary",
        hx_post="/upload",
        hx_encoding="multipart/form-data",
        hx_include="[name='file']"
    )
)

Bootstrap CSS Classes Explained

Core InputGroup Classes

Class Purpose Applied To
.input-group Container - Wraps input and addons <div> wrapper
.input-group-lg Large size - Bigger inputs and addons .input-group
.input-group-sm Small size - Compact inputs and addons .input-group
.input-group-text Text addon - Styles text/icon addons <span> for text
.form-control Input styling - Must be on input element <input>, <select>, <textarea>
.btn Button addon - Styles button addons <button> elements

Layout Classes

Class Purpose Effect
.flex-nowrap Prevent wrapping - Keep on one line Prevents wrapping on small screens
.mb-3 Margin bottom - Spacing between groups Standard form spacing

Responsive InputGroup Patterns

Mobile-Friendly Input Groups

# Stack on mobile, inline on desktop
InputGroup(
    InputGroupText("$"),
    Input("amount", input_type="number"),
    Button("Submit", variant="primary"),
    cls="flex-wrap flex-md-nowrap"  # Wrap on mobile, nowrap on desktop
)

Core Faststrap Features

Global Defaults with set_component_defaults

from faststrap import set_component_defaults, InputGroup

# All input groups large by default
set_component_defaults("InputGroup", size="lg")

# Now all input groups inherit large size
InputGroup(
    InputGroupText("@"),
    Input("username")
)  # ← Automatically size="lg"

Common Recipes

The "Copy to Clipboard" Pattern

from faststrap import InputGroup, Input, Button, Icon

def CopyableInput(value: str, label: str = "Copy"):
    return InputGroup(
        Input("copy_value", value=value, readonly=True),
        Button(
            Icon("clipboard"),
            label,
            variant="outline-secondary",
            onclick=f"navigator.clipboard.writeText('{value}'); this.textContent='Copied!'; setTimeout(()=>this.textContent='{label}',2000)"
        )
    )

# Usage
CopyableInput("https://example.com/share/abc123")

The "Unit Selector" Pattern

from faststrap import InputGroup, Input, Select

InputGroup(
    Input("value", input_type="number", placeholder="0"),
    Select(
        "unit",
        ("kg", "Kilograms"),
        ("lb", "Pounds"),
        ("oz", "Ounces"),
        cls="form-select"
    )
)

Accessibility Best Practices

Automatic Features: - Proper form control structure - Label associations (use with labels) - Keyboard navigation

Manual Enhancements:

InputGroup(
    InputGroupText("@", aria_label="Username prefix"),
    Input("username", placeholder="Username", aria_label="Username")
)

Parameter Reference

InputGroup

Parameter Type Default Description
*children Any Required Form controls and addons
size "sm" \| "lg" \| None None Group size
nowrap bool False Prevent wrapping
**kwargs Any - Additional HTML attributes

InputGroupText

Parameter Type Default Description
*children Any Required Text or icon content
**kwargs Any - Additional HTML attributes

faststrap.components.forms.inputgroup.InputGroup(*children, size=None, nowrap=False, **kwargs)

Bootstrap InputGroup component.

Extend form controls with text, buttons, or other elements.

Parameters:

Name Type Description Default
*children Any

Form controls and addons (InputGroupText, Button, Input, etc.)

()
size SizeType | None

Group size (sm, lg)

None
nowrap bool

Prevent wrapping on smaller screens

False
**kwargs Any

Additional HTML attributes

{}

Returns:

Type Description
Div

FastHTML Div element with input-group structure

Example

With text addon:

InputGroup( ... InputGroupText("@"), ... Input("username", placeholder="Username"), ... )

With button:

InputGroup( ... Input("search", placeholder="Search..."), ... Button("Go", variant="primary"), ... )

Large size:

InputGroup( ... InputGroupText("$"), ... Input("amount", input_type="number"), ... InputGroupText(".00"), ... size="lg" ... )

See Also

Bootstrap docs: https://getbootstrap.com/docs/5.3/forms/input-group/

Source code in src/faststrap/components/forms/inputgroup.py
@register(category="forms")
def InputGroup(
    *children: Any,
    size: SizeType | None = None,
    nowrap: bool = False,
    **kwargs: Any,
) -> Div:
    """Bootstrap InputGroup component.

    Extend form controls with text, buttons, or other elements.

    Args:
        *children: Form controls and addons (InputGroupText, Button, Input, etc.)
        size: Group size (sm, lg)
        nowrap: Prevent wrapping on smaller screens
        **kwargs: Additional HTML attributes

    Returns:
        FastHTML Div element with input-group structure

    Example:
        With text addon:
        >>> InputGroup(
        ...     InputGroupText("@"),
        ...     Input("username", placeholder="Username"),
        ... )

        With button:
        >>> InputGroup(
        ...     Input("search", placeholder="Search..."),
        ...     Button("Go", variant="primary"),
        ... )

        Large size:
        >>> InputGroup(
        ...     InputGroupText("$"),
        ...     Input("amount", input_type="number"),
        ...     InputGroupText(".00"),
        ...     size="lg"
        ... )

    See Also:
        Bootstrap docs: https://getbootstrap.com/docs/5.3/forms/input-group/
    """
    # Build classes
    classes = ["input-group"]

    if size:
        classes.append(f"input-group-{size}")

    if nowrap:
        classes.append("flex-nowrap")

    user_cls = kwargs.pop("cls", "")
    all_classes = merge_classes(" ".join(classes), user_cls)

    # Build attributes
    attrs: dict[str, Any] = {"cls": all_classes}
    attrs.update(convert_attrs(kwargs))

    return Div(*children, **attrs)

faststrap.components.forms.inputgroup.InputGroupText(*children, **kwargs)

Bootstrap InputGroup Text addon.

Text or icon addon for InputGroup.

Parameters:

Name Type Description Default
*children Any

Text or icon content

()
**kwargs Any

Additional HTML attributes

{}

Returns:

Type Description
Span

FastHTML Span element with input-group-text class

Example

InputGroupText("@") InputGroupText("$") InputGroupText(Icon("search"))

Source code in src/faststrap/components/forms/inputgroup.py
@register(category="forms")
def InputGroupText(
    *children: Any,
    **kwargs: Any,
) -> Span:
    """Bootstrap InputGroup Text addon.

    Text or icon addon for InputGroup.

    Args:
        *children: Text or icon content
        **kwargs: Additional HTML attributes

    Returns:
        FastHTML Span element with input-group-text class

    Example:
        >>> InputGroupText("@")
        >>> InputGroupText("$")
        >>> InputGroupText(Icon("search"))
    """
    user_cls = kwargs.pop("cls", "")
    all_classes = merge_classes("input-group-text", user_cls)

    attrs: dict[str, Any] = {"cls": all_classes}
    attrs.update(convert_attrs(kwargs))

    return Span(*children, **attrs)

faststrap.components.forms.inputgroup.FloatingLabel(name, *, label, input_type='text', value='', placeholder='', disabled=False, readonly=False, required=False, input_id=None, input_cls='', label_cls='', **kwargs)

Bootstrap FloatingLabel input component.

An input with an animated floating label that moves when focused.

Parameters:

Name Type Description Default
name str

Input name attribute

required
label str

Label text (required for floating labels)

required
input_type Literal['text', 'password', 'email', 'number', 'url', 'tel', 'search', 'date', 'time', 'datetime-local']

HTML input type

'text'
value str

Initial value

''
placeholder str

Placeholder text (usually same as label)

''
disabled bool

Disable the input

False
readonly bool

Make input read-only

False
required bool

Mark as required field

False
input_id str | None

ID for the input (auto-generated from name if not provided)

None
input_cls str

Additional classes for input element

''
label_cls str

Additional classes for label element

''
**kwargs Any

Additional HTML attributes

{}

Returns:

Type Description
Div

FastHTML Div element with form-floating structure

Example

Basic:

FloatingLabel("email", label="Email address", input_type="email")

With value:

FloatingLabel("name", label="Your name", value="John Doe")

Password:

FloatingLabel("password", label="Password", input_type="password", required=True)

See Also

Bootstrap docs: https://getbootstrap.com/docs/5.3/forms/floating-labels/

Source code in src/faststrap/components/forms/inputgroup.py
@register(category="forms")
def FloatingLabel(
    name: str,
    *,
    label: str,
    input_type: Literal[
        "text",
        "password",
        "email",
        "number",
        "url",
        "tel",
        "search",
        "date",
        "time",
        "datetime-local",
    ] = "text",
    value: str = "",
    placeholder: str = "",
    disabled: bool = False,
    readonly: bool = False,
    required: bool = False,
    input_id: str | None = None,
    input_cls: str = "",
    label_cls: str = "",
    **kwargs: Any,
) -> Div:
    """Bootstrap FloatingLabel input component.

    An input with an animated floating label that moves when focused.

    Args:
        name: Input name attribute
        label: Label text (required for floating labels)
        input_type: HTML input type
        value: Initial value
        placeholder: Placeholder text (usually same as label)
        disabled: Disable the input
        readonly: Make input read-only
        required: Mark as required field
        input_id: ID for the input (auto-generated from name if not provided)
        input_cls: Additional classes for input element
        label_cls: Additional classes for label element
        **kwargs: Additional HTML attributes

    Returns:
        FastHTML Div element with form-floating structure

    Example:
        Basic:
        >>> FloatingLabel("email", label="Email address", input_type="email")

        With value:
        >>> FloatingLabel("name", label="Your name", value="John Doe")

        Password:
        >>> FloatingLabel("password", label="Password", input_type="password", required=True)

    See Also:
        Bootstrap docs: https://getbootstrap.com/docs/5.3/forms/floating-labels/
    """
    fl_id = input_id or f"floating-{name}"

    user_cls = kwargs.pop("cls", "")
    wrapper_cls = merge_classes("form-floating", user_cls)

    # Input classes and attributes
    all_input_cls = merge_classes("form-control", input_cls)

    input_attrs: dict[str, Any] = {
        "type": input_type,
        "cls": all_input_cls,
        "name": name,
        "id": fl_id,
        "placeholder": placeholder or label,  # Placeholder required for floating effect
    }

    if value:
        input_attrs["value"] = value
    if disabled:
        input_attrs["disabled"] = True
    if readonly:
        input_attrs["readonly"] = True
    if required:
        input_attrs["required"] = True

    input_attrs.update(convert_attrs(kwargs))

    # Label
    label_cls_final = merge_classes("", label_cls) if label_cls else None

    label_attrs: dict[str, Any] = {"fr": fl_id}
    if label_cls_final:
        label_attrs["cls"] = label_cls_final

    return Div(
        FTInput(**input_attrs),
        Label(label, **label_attrs),
        cls=wrapper_cls,
    )