Field

Wraps form inputs with labels, descriptions, and validation feedback.

Basic Usage

<c-ui.field>
    <c-ui.label>Email</c-ui.label>
    <c-ui.input type="email" name="email" placeholder="you@example.com" />
    <c-ui.error name="email" />
</c-ui.field>
{% cotton ui.field %}
    {% cotton ui.label %}Email{% endcotton %}
    {% cotton ui.input type="email" name="email" placeholder="you@example.com" /%}
    {% cotton ui.error name="email" /%}
{% endcotton %}

Shorthand Usage

To reduce repetitive markup, form controls like input and textarea can accept label, description, error, and badge props directly. When any of these props are provided, the control will automatically be wrapped in a field structure.

Must be at least 8 characters
Tell us about yourself
<c-ui.input
    label="Email Address"
    type="email"
    name="email"
    placeholder="Enter your email"
/>

<c-ui.input
    label="Password"
    badge="Required"
    description_trailing="Must be at least 8 characters"
    type="password"
    name="password"
    placeholder="•••••••••"
/>

<c-ui.textarea
    label="Bio"
    description="Tell us about yourself"
    name="bio"
    placeholder="Write something..."
/>
{% cotton ui.input
    label="Email Address"
    type="email"
    name="email"
    placeholder="Enter your email"
/%}

{% cotton ui.input
    label="Password"
    badge="Required"
    description_trailing="Must be at least 8 characters"
    type="password"
    name="password"
    placeholder="•••••••••"
/%}

{% cotton ui.textarea
    label="Bio"
    description="Tell us about yourself"
    name="bio"
    placeholder="Write something..."
/%}

With Label Badge

Add a badge to the label to indicate required or optional fields.

<c-ui.field>
    <c-ui.label badge="Required">Full Name</c-ui.label>
    <c-ui.input type="text" name="name" placeholder="John Doe" />
</c-ui.field>

<c-ui.field>
    <c-ui.label badge="Optional">Phone Number</c-ui.label>
    <c-ui.input type="tel" name="phone" placeholder="+1 (555) 000-0000" />
</c-ui.field>
{% cotton ui.field %}
    {% cotton ui.label badge="Required" %}Full Name{% endcotton %}
    {% cotton ui.input type="text" name="name" placeholder="John Doe" /%}
{% endcotton %}

{% cotton ui.field %}
    {% cotton ui.label badge="Optional" %}Phone Number{% endcotton %}
    {% cotton ui.input type="tel" name="phone" placeholder="+1 (555) 000-0000" /%}
{% endcotton %}

With Description

Add helper text to provide context about the field. Descriptions can appear before or after the input.

This will be your public display name.
We'll send confirmation to this address.
{# Description before input #}
<c-ui.field>
    <c-ui.label>Username</c-ui.label>
    <c-ui.description>This will be your public display name.</c-ui.description>
    <c-ui.input type="text" name="username" placeholder="johndoe" />
</c-ui.field>

{# Description after input (trailing) #}
<c-ui.field>
    <c-ui.label>Email</c-ui.label>
    <c-ui.input type="email" name="email" placeholder="you@example.com" />
    <c-ui.description>We'll send confirmation to this address.</c-ui.description>
</c-ui.field>
{# Description before input #}
{% cotton ui.field %}
    {% cotton ui.label %}Username{% endcotton %}
    {% cotton ui.description %}This will be your public display name.{% endcotton %}
    {% cotton ui.input type="text" name="username" placeholder="johndoe" /%}
{% endcotton %}

{# Description after input (trailing) #}
{% cotton ui.field %}
    {% cotton ui.label %}Email{% endcotton %}
    {% cotton ui.input type="email" name="email" placeholder="you@example.com" /%}
    {% cotton ui.description %}We'll send confirmation to this address.{% endcotton %}
{% endcotton %}

With Error Message

Display validation feedback with the error component. Supports Django form integration or explicit messages.

Password must be at least 8 characters.
{# With explicit message #}
<c-ui.field>
    <c-ui.label>Password</c-ui.label>
    <c-ui.input type="password" name="password" placeholder="•••••••••" />
    <c-ui.error message="Password must be at least 8 characters." />
</c-ui.field>

{# With Django form integration #}
<c-ui.field>
    <c-ui.label>Email</c-ui.label>
    <c-ui.input type="email" name="email" />
    <c-ui.error name="email" :form="form" />
</c-ui.field>
{# With explicit message #}
{% cotton ui.field %}
    {% cotton ui.label %}Password{% endcotton %}
    {% cotton ui.input type="password" name="password" placeholder="•••••••••" /%}
    {% cotton ui.error message="Password must be at least 8 characters." /%}
{% endcotton %}

{# With Django form integration #}
{% cotton ui.field %}
    {% cotton ui.label %}Email{% endcotton %}
    {% cotton ui.input type="email" name="email" /%}
    {% cotton ui.error name="email" :form="form" /%}
{% endcotton %}

Complete Example

Combining all elements together with Django form integration.

Must include at least 8 characters with uppercase, lowercase, and numbers.
<c-ui.field>
    <c-ui.label badge="Required">Password</c-ui.label>
    <c-ui.description>
        Must include at least 8 characters with uppercase, lowercase, and numbers.
    </c-ui.description>
    <c-ui.input type="password" name="password" placeholder="•••••••••" />
    <c-ui.error name="password" />
</c-ui.field>
{% cotton ui.field %}
    {% cotton ui.label badge="Required" %}Password{% endcotton %}
    {% cotton ui.description %}
        Must include at least 8 characters with uppercase, lowercase, and numbers.
    {% endcotton %}
    {% cotton ui.input type="password" name="password" placeholder="•••••••••" /%}
    {% cotton ui.error name="password" /%}
{% endcotton %}

Layouts

The default block layout stacks the label above the control. Two named shortcuts cover the common alternatives: inline sits the label beside the control, and toggle pushes the control to the far right (ideal for switches and checkboxes). The Switch uses the toggle layout for its own inline prop.

These shortcuts only exist because they encode flex wiring that is awkward to repeat by hand. They are deliberately few: for anything outside them, pass utility classes on the field rather than waiting for a new variant to be invented.

Get notified about activity.
{# block: label above control (default) #}
<c-ui.field>
    <c-ui.label>Email</c-ui.label>
    <c-ui.input type="email" name="email" placeholder="you@example.com" />
</c-ui.field>

{# inline: label beside control #}
<c-ui.field variant="inline">
    <c-ui.label class="w-24 pt-2">Email</c-ui.label>
    <div class="flex-1">
        <c-ui.input type="email" name="email" placeholder="you@example.com" />
    </div>
</c-ui.field>

{# toggle: control pushed to the far right #}
<c-ui.field variant="toggle" label="Email alerts" description="Get notified about activity.">
    <c-ui.switch name="alerts" />
</c-ui.field>

{# escape hatch: override classes for anything else #}
<c-ui.field class="flex flex-row-reverse items-center gap-3">
    ...
</c-ui.field>
{# block: label above control (default) #}
{% cotton ui.field %}
    {% cotton ui.label %}Email{% endcotton %}
    {% cotton ui.input type="email" name="email" placeholder="you@example.com" /%}
{% endcotton %}

{# inline: label beside control #}
{% cotton ui.field variant="inline" %}
    {% cotton ui.label class="w-24 pt-2" %}Email{% endcotton %}
    <div class="flex-1">
        {% cotton ui.input type="email" name="email" placeholder="you@example.com" /%}
    </div>
{% endcotton %}

{# toggle: control pushed to the far right #}
{% cotton ui.field variant="toggle" label="Email alerts" description="Get notified about activity." %}
    {% cotton ui.switch name="alerts" /%}
{% endcotton %}

{# escape hatch: override classes for anything else #}
{% cotton ui.field class="flex flex-row-reverse items-center gap-3" %}
    ...
{% endcotton %}

API Reference

Field Props

Name Description Type Options Default
variant Layout variant. 'block' stacks the label above the control, 'inline' sits the label beside it, 'toggle' pushes the control to the far right. For anything else, pass utility classes via class. str
blockinlinetoggle
block
class Utility classes merged onto the field wrapper. The escape hatch for layouts the variants don't cover. str

Label Props

Name Description Type Options Default
badge Badge text like 'Required' or 'Optional'. str
for ID of the associated input element. str

Description Props

Name Description Type Options Default
slot (default) Helper text content - no props available.

Error Props

Name Description Type Options Default
name Field name to lookup in form.errors. Use '__all__' for non-field errors. str
:form Django form instance. When provided with name, automatically displays validation errors from form.errors. Form None
message Explicit error message to display. Bypasses form integration. str

Badge Props

Name Description Type Options Default
color Badge color variant. str
zincredorangeamberyellowlimegreenemeraldtealcyanskyblueindigovioletpurplefuchsiapinkrose
zinc
size Badge size. str
smlg
variant Badge style variant. str
pillsolid
:inset Apply negative margins. bool
TrueFalse
False