Skip to content

Form control ​

This component is a monster, CSS-wise. That is due to the fact that this component styles more than the wrapper it's applied to – it style all kinds of form controls (<input>, <select>, <textarea>) within it. Why? Well, in some cases the text fields or checkboxes are output via some server rendered code where styling them directly is complicated. To add a wrapper class is therefore more convenient. Also, you don't have to change and markup if your inputs change from say type="text" to type="search".

When to use it ​

Add a <div class="c-form-control"> around every form input, is the general recommendation.

Variants ​

When displaying form controls next to each other, adding c-form-control--inline can be a solution. There may also be a need for smaller och larger text input and that's when c-form-control--small or c-form-control--large variants come in handy.

A c-form-control--compact variant exists as well for when the label is supposed to be on top of the text input.

When c-form-control--group is applied the buttons get grouped together with the input field. If no input is present, the buttons stay rounded at the start en end of the group but "glued together" visually.

TIP

To override the default border radius, set --input-radius to a different value.

Checkboxes and radios follow the framework theme and have visible hover, active and keyboard focus states. Checked and indeterminate controls keep their native rendering and can vary between browsers and operating systems. Use --selected-color or --label-color to customize their color.

Use .has-error on the wrapper, or .input-validation-error or aria-invalid="true" on the input, to show an error state. Browser validation through :user-invalid is also supported. Use the input's disabled attribute for unavailable controls.

Use multiple for a native multiple select. On iOS, tapping the field opens the system's multiple-choice picker. On desktop, use size to control the listbox's visible rows. Add data-disable-search to keep legacy ChosenJS from replacing the select. For the Vue search component, see Select search.

Selected, hovered and focused options follow the framework theme for both single and multiple selects where the browser allows it. Native popup menus, Safari listboxes and iOS system pickers can still use system selection colors.

Native date and time pickers follow the light or dark theme where the browser supports it. Use .t-light or .t-dark on the page or a surrounding container to override the system preference. The browser controls the picker palette.

What it looks like ​

INFO

This component also has a small legacy JS companion in components.form.js. It automatically initializes ChosenJS on <select> elements inside .c-form-control, both on page load and when newcontent is triggered. The searchability of some of the <select>s in the preview above comes from that behavior. To disable it for a specific <select>, use a data-disable-search attribute.

Code examples ​

html
<div class="c-form-control">
    <label for="id5" class="c-label">Normal label</label>
    <input id="id5" type="text" />
</div>
html
<div class="c-form-control c-form-control--small">
    <label for="id5b" class="c-label">Normal label</label>
    <input id="id5b" type="text" />
</div>
html
<div class="c-form-control c-form-control--compact">
    <label for="id6" class="c-label">Normal label</label>
    <input id="id6" type="text" />
</div>
html
<div class="c-form-control has-error">
    <label for="id7" class="c-label">Normal label, error</label>
    <input id="id7" type="text" class="input-validation-error" />
    <span class="c-box c-box--small c-box--negative">Form error message</span>
</div>
html
<div class="c-form-control c-form-control--compact c-form-control--group">
    <label for="id94b" class="c-label">E-mail (with value)</label>
    <input id="id94b" type="email" value="test@example.com" />
    <input class="c-button c-button--primary" type="submit" value="Submit" />
</div>
html
<div class="c-form-control">
    <input id="checkbox-example" type="checkbox" />
    <label for="checkbox-example" class="c-label">Checkbox</label>
</div>
html
<div class="c-form-control has-error">
    <input id="checkbox-error-example" type="checkbox" aria-invalid="true" aria-describedby="checkbox-error-message" />
    <label for="checkbox-error-example" class="c-label">Checkbox, error</label>
    <span id="checkbox-error-message" class="c-box c-box--small c-box--negative">Form error message</span>
</div>
html
<div class="c-form-control">
    <input id="radio-example" type="radio" name="choice-example" />
    <label for="radio-example" class="c-label">Radio</label>
</div>
html
<div class="c-form-control">
    <label class="c-label" for="native-multiple-example">Countries</label>
    <select id="native-multiple-example" name="countries" multiple size="4" data-disable-search>
        <option value="dk" selected>Denmark</option>
        <option value="se" selected>Sweden</option>
        <option value="no">Norway</option>
        <option value="fi">Finland</option>
    </select>
</div>

Accessibility notes ​

In forced colors mode, checkboxes and radios keep native rendering for all states, and select options use the user's system colors.

When creating forms, it is crucial to establish a clear relationship between form fields and their corresponding error messages. This ensures that assistive technologies, such as screen readers, can accurately convey the error information to users with disabilities. By using appropriate ARIA attributes like aria-describedby or linking the error message to the input field, you enhance the accessibility and usability of your forms for all users.