View as Markdown

Form

A set of layout wrappers to build accessible forms with label, description and error-message slots.

100%
Loading...
<twig:Form class="mx-auto w-full max-w-md">
    <twig:Form:Item>
        <twig:Form:Label for="form-email">Email</twig:Form:Label>
        <twig:Input id="form-email" name="email" type="email" placeholder="you@example.com" />
        <twig:Form:Description>We'll never share your email with anyone else.</twig:Form:Description>
    </twig:Form:Item>
    <twig:Form:Item>
        <twig:Form:Label for="form-bio">Bio</twig:Form:Label>
        <twig:Textarea id="form-bio" name="bio" placeholder="Tell us a bit about yourself" />
        <twig:Form:Description>You can @mention other users and organizations.</twig:Form:Description>
    </twig:Form:Item>
    <div class="flex justify-end gap-2">
        <twig:Button type="button" variant="outline">Cancel</twig:Button>
        <twig:Button type="submit">Save</twig:Button>
    </div>
</twig:Form>

Installation

php bin/console ux:install form --kit shadcn

Install the following Composer dependencies:

composer require twig/html-extra:^3.24.0 symfony/ux-twig-component:^3.5 tales-from-a-dev/twig-tailwind-extra:^1.3.0

Copy the following file(s) into your app:

templates/components/Form.html.twig
{# @block content The form fields, typically a list of `Form:Item`. #}
<form
    data-slot="form"
    {{ attributes.defaults({
        class: 'space-y-6'|tailwind_classes,
    }) }}
>
    {%- block content %}{% endblock -%}
</form>
templates/components/Form/Description.html.twig
{# @block content The help text. #}
<p
    data-slot="form-description"
    {{ attributes.defaults({
        class: 'text-sm text-muted-foreground'|tailwind_classes,
    }) }}
>
    {%- block content %}{% endblock -%}
</p>
templates/components/Form/Item.html.twig
{# @block content A `Form:Label`, a form control, an optional `Form:Description` and an optional `Form:Message`. #}
<div
    data-slot="form-item"
    {{ attributes.defaults({
        class: 'group/form-item grid gap-2'|tailwind_classes,
    }) }}
>
    {%- block content %}{% endblock -%}
</div>
templates/components/Form/Label.html.twig
{# @block content The label text. #}
<label
    data-slot="form-label"
    {{ attributes.defaults({
        class: 'flex items-center gap-2 text-sm font-medium leading-none select-none group-has-[[data-slot=form-message]]/form-item:text-destructive'|tailwind_classes,
    }) }}
>
    {%- block content %}{% endblock -%}
</label>
templates/components/Form/Message.html.twig
{# @block content The validation error message. #}
<p
    data-slot="form-message"
    {{ attributes.defaults({
        class: 'text-sm text-destructive'|tailwind_classes,
    }) }}
>
    {%- block content %}{% endblock -%}
</p>

Usage

<twig:Form>
    <twig:Form:Item>
        <twig:Form:Label for="form-username">Username</twig:Form:Label>
        <twig:Input id="form-username" name="username" placeholder="shadcn" />
        <twig:Form:Description>This is your public display name.</twig:Form:Description>
    </twig:Form:Item>
    <twig:Button type="submit">Submit</twig:Button>
</twig:Form>

Examples

Validation

When a Form:Item contains a Form:Message, its Form:Label switches to the destructive color.

100%
Loading...
<twig:Form class="mx-auto w-full max-w-md">
    <twig:Form:Item>
        <twig:Form:Label for="form-validation-email">Email</twig:Form:Label>
        <twig:Input id="form-validation-email" name="email" type="email" value="not-an-email" aria-invalid="true" />
        <twig:Form:Message>Please enter a valid email address.</twig:Form:Message>
    </twig:Form:Item>
</twig:Form>

API Reference

<twig:Form>

Block Description
content The form fields, typically a list of Form:Item.

<twig:Form:Description>

Block Description
content The help text.

<twig:Form:Item>

Block Description
content A Form:Label, a form control, an optional Form:Description and an optional Form:Message.

<twig:Form:Label>

Block Description
content The label text.

<twig:Form:Message>

Block Description
content The validation error message.