Composer

A chat-style input: a focusable shell wrapping an auto-growing textarea and a row of actions.

Basic

On its own the composer is an auto-growing textarea inside a shell that takes the focus ring. Type to watch it grow.

<c-ui.composer placeholder="Write a comment…" />
{% cotton ui.composer placeholder="Write a comment…" /%}

Prompt box

Fill the leading and trailing slots to build a prompt box. The whole shell stays lit while any control inside it is focused.

<c-ui.composer placeholder="Ask anything…">
    <c-slot name="leading">
        <c-ui.button variant="ghost" size="sm" class="!px-2" aria-label="Add">
            <svg><!-- plus --></svg>
        </c-ui.button>
    </c-slot>
    <c-slot name="trailing">
        <span class="px-1 text-sm text-zinc-500">Opus 4.8</span>
        <c-ui.button variant="ghost" size="sm" class="!px-2" aria-label="Dictate">
            <svg><!-- mic --></svg>
        </c-ui.button>
        <c-ui.button variant="primary" size="sm" class="!px-2" aria-label="Send">
            <svg><!-- arrow-up --></svg>
        </c-ui.button>
    </c-slot>
</c-ui.composer>
{% cotton ui.composer placeholder="Ask anything…" %}
    {% cotton:slot leading %}
        {% cotton ui.button variant="ghost" size="sm" class="!px-2" aria-label="Add" %}
            <svg><!-- plus --></svg>
        {% endcotton %}
    {% endcotton:slot %}
    {% cotton:slot trailing %}
        <span class="px-1 text-sm text-zinc-500">Opus 4.8</span>
        {% cotton ui.button variant="ghost" size="sm" class="!px-2" aria-label="Dictate" %}
            <svg><!-- mic --></svg>
        {% endcotton %}
        {% cotton ui.button variant="primary" size="sm" class="!px-2" aria-label="Send" %}
            <svg><!-- arrow-up --></svg>
        {% endcotton %}
    {% endcotton:slot %}
{% endcotton %}

How it works

  • One focusable surface. The shell shows the focus ring with focus-within, so focusing the textarea (or a button inside) lights the whole box like a single input.
  • Transparent textarea. The textarea is borderless and transparent (--color-input-bg), so it reads as part of the shell rather than a nested field.
  • Auto-grows. A small Alpine helper resizes the textarea to its content as you type, up to a max height, then scrolls.
  • Plain text. It is a real <textarea>, so it submits in forms and stays accessible. For rich content (mentions, inline pills) reach for a dedicated editor instead.

Reference

Props

Name Description Type Options Default
name Form field name for the textarea. str
placeholder Placeholder text. str Send a message…
value Initial textarea content. str
variant raised fills the surface so it sits above the page in both light and dark; flush uses the transparent field fill (flat in light, faintly lifted in dark) to match form inputs. str
raisedflush
raised
rows Initial visible rows before auto-grow takes over. str 2
:disabled Dim and disable the input. bool
TrueFalse
False

Slots

Name Description Type Options Default
leading Actions on the left of the toolbar row (e.g. an attach button). slot
trailing Actions on the right of the toolbar row (e.g. a model picker, mic, send). slot

Any extra attributes (e.g. x-model, maxlength, hx-*) are forwarded to the underlying <textarea>.