Origami Frontend Components & Services

Readme: o-forms

FT-branded styles for form elements.



Each form field is made up of at least 3 elements:

<div class="o-forms">
    <label for="o-forms-demo-text" class="o-forms__label">Text input example</label>
    <input type="text" id="o-forms-demo-text" class="o-forms__text" required />

Additonal field information

It is possible to add additional information to form fields with .o-forms__additional-info. Additonal information is not limited to a text input, it could also apply against a select, textarea, checkbox, etc.

<div class="o-forms">
    <label for="o-forms-demo-additional" class="o-forms__label">Text input example</label>
    <div class="o-forms__additional-info">Additional info follows the label if required.</div>
    <input type="text" id="o-forms-demo-additional" class="o-forms__text" required />

Optional fields

To indicate to the user that a field is optional, add the .o-forms__label--optional class to the label of the field. Any field label can be marked optional in this way.

<div class="o-forms">
    <label for="o-forms-demo-optional" class="o-forms__label o-forms__label--optional">Optional  input example</label>
    <input type="text" id="o-forms-demo-optional" class="o-forms__text" />

Wide fields

The class .o-forms--wide can be used to show form fields without width restrictions. This is demonstrated below with a text input but can apply to any .o-forms field.

<div class="o-forms o-forms--wide">
    <label for="o-forms-full" class="o-forms__label">Text input full width</label>
    <input type="text" id="o-forms-full" class="o-forms__text o-forms__text--valid" value="Field value" />

Text inputs

The markup above demonstrates how to use text inputs. More text input examples are available on the Origami Registry.


<div class="o-forms">
    <label for="o-forms-demo-textarea" class="o-forms__label">Textarea</label>
    <textarea id="o-forms-demo-textarea" class="o-forms__textarea"></textarea>

Textarea examples

Select boxes

<div class="o-forms">
    <label for="o-forms-demo-select" class="o-forms__label">Select box</label>
    <select id="o-forms-demo-select" class="o-forms__select">
        <option value="option1" selected>Option 1</option>
        <option value="option2">Option 2</option>
        <option value="option3">Option 3</option>
        <option value="option4">Option 4</option>

Select boxes examples

Checkbox and radio controls

Unlike other inputs, multiple checkbox and radio inputs should be wrapped in .o-forms__group to ensure correct vertical spacing.

<!-- Radio -->
<fieldset class="o-forms">
    <legend class="o-forms__label">Default radio controls</legend>
    <div class="o-forms__additional-info">Prompt text follows the legend if required.</div>
    <div class="o-forms__group">
        <input type="radio" name="radio" value="1" class="o-forms__radio" id="radio11" checked="checked" />
        <label for="radio11" class="o-forms__label">Radio 1</label>
        <input type="radio" name="radio" value="2" class="o-forms__radio" id="radio12" />
        <label for="radio12" class="o-forms__label">Radio 2</label>

<!-- Checkboxes -->
<fieldset class="o-forms">
    <legend class="o-forms__label">Default checkboxes</legend>
    <div class="o-forms__group">
        <input type="checkbox" name="checkbox" value="1" class="o-forms__checkbox" id="checkbox11" checked="checked" />
        <label for="checkbox11" class="o-forms__label">Checkbox 1</label>
        <input type="checkbox" name="checkbox" value="2" class="o-forms__checkbox" id="checkbox12" />
        <label for="checkbox12" class="o-forms__label">Checkbox 2</label>
        <input type="checkbox" name="checkbox" value="3" class="o-forms__checkbox" id="checkbox13" />
        <label for="checkbox13" class="o-forms__label">Checkbox 3</label>

To display checkboxes/radios inline add .o-forms__group--inline to their group wrapper.

<!-- Inline Radio -->
<fieldset class="o-forms">
    <legend class="o-forms__label">Radio controls inline</legend>
    <div class="o-forms__group o-forms__group--inline">
        <input type="radio" name="radio" value="1" class="o-forms__radio" id="radio41" checked="checked" />
        <label for="radio41" class="o-forms__label">Radio 1</label>
        <input type="radio" name="radio" value="2" class="o-forms__radio" id="radio42" />
        <label for="radio42" class="o-forms__label">Radio 2</label>

<!-- Inline Checkboxes -->
<fieldset class="o-forms">
    <legend class="o-forms__label">Inline checkboxes</legend>
    <div class="o-forms__group o-forms__group--inline">
        <input type="checkbox" name="checkbox" value="1" class="o-forms__checkbox" id="checkbox61" checked="checked" />
        <label for="checkbox61" class="o-forms__label">Checkbox 1</label>
        <input type="checkbox" name="checkbox" value="2" class="o-forms__checkbox" id="checkbox62" />
        <label for="checkbox62" class="o-forms__label">Checkbox 2</label>

Radio control examples
Checkbox examples

Styled radio buttons

To produce styled radio buttons wrap radio inputs with .o-forms__group .o-forms__group--inline-together and use the class .o-forms__radio-button on the radio input.

<!-- Styled radio buttons -->
<fieldset class="o-forms">
    <legend class="o-forms__label">Styled radio buttons with a default selection</legend>
    <div class="o-forms__group o-forms__group--inline-together">
        <input type="radio" name="radio5" value="daily" class="o-forms__radio-button" id="radio51"
               checked="checked" />
        <label for="radio51" class="o-forms__label">Daily</label>
        <input type="radio" name="radio5" value="weekly" class="o-forms__radio-button" id="radio52" />
        <label for="radio52" class="o-forms__label">Weekly</label>
        <input type="radio" name="radio5" value="monthly" class="o-forms__radio-button" id="radio53" />
        <label for="radio53" class="o-forms__label">Monthly</label>

Styled radio button examples


Suffixes are used to append content to an input, i.e. a button. Add a wrapper .o-forms__affix-wrapper to contain both the input and its suffix .o-forms__suffix. The suffix .o-forms__suffix wraps suffix content, i.e. a button.

<div class="o-forms">
    <label class="o-forms__label" for="text-suffix">Text input with suffix button</label>
    <div class="o-forms__affix-wrapper">
        <input id="text-suffix" type="text" class="o-forms__text" />
        <div class="o-forms__suffix">
            <button type="button" class="o-buttons o-buttons--secondary o-buttons--big">Go</button>

Suffixes examples

Toggles (checkbox toggles)

To produce a toggle interface wrap checkboxes in .o-forms__toggle and add the data attribute data-o-form-toggle to the checkbox input.

<!-- Toggle -->
<fieldset class="o-forms">
    <legend class="o-forms__label">Checkbox Toggle</legend>
    <div class="o-forms__group">
        <div class="o-forms__toggle">
            <input class="o-forms__toggle__checkbox" data-o-form-toggle type="checkbox" name="checkbox" value="1" id="checkboxToggle1" />
            <label for="checkboxToggle1" class="o-forms__label">Checkbox Toggle 1</label>
        <div class="o-forms__toggle">
            <input class="o-forms__toggle__checkbox" data-o-form-toggle type="checkbox" name="checkbox" value="1" id="checkboxToggle2" checked="checked" />
            <label for="checkboxToggle2" class="o-forms__label">Checkbox Toggle 2</label>

Toggle examples

Validation states

Validation styles are applied by adding .o-forms--error or .o-forms--valid to the field's containing element (typically, .o-forms). Child .o-forms__label, .o-forms__text, .o-forms__select, .o-forms__checkbox, .o-forms__radio, .o-forms__textarea elements will be styled appropriately.

An error message, defined with .o-forms__errortext, can be appended to the containing element.

<div class="o-forms o-forms--error">
    <label class="o-forms__label">Text input</label>
    <input type="text" class="o-forms__text" />
    <div class="o-forms__errortext">Please enter a valid url</div>


Wrap a group of .o-forms fields in a section .o-forms-section to highlight them and provide a global message.

<div class="o-forms-section">
    <div class="o-forms-section__message">
        <p>This is a section message.</p>
    <div class="o-forms">
        <label for="o-forms-message" class="o-forms__label">Field Label</label>
        <input type="text" id="o-forms-message" class="o-forms__text" required />

This can be used to highlight errors within a section of a form which contains multiple .o-forms fields.

<div class="o-forms-section o-forms-section--error">
    <div class="o-forms-section__message">
        <p>This is a section error message</p>
    <div class="o-forms o-forms--error">
        <label for="o-forms-section-error" class="o-forms__label">Field Label</label>
        <input type="text" id="o-forms-section-error" class="o-forms__text" required />
        <div class="o-forms__errortext">Invalid entry</div>

Add .o-forms-section--wide to remove max width restrictions.

Section examples

Additional Features

Additional features such as small text and select inputs are avalible. Please see more examples on the Origami Registry.


Silent mode

In silent mode o-forms provides mixins for each set of form fields as well as some mixins to output basic form styles in one large chunk.

The oForms mixin will output all features of o-forms. Turn off silent mode to output all o-forms features using this mixin automatically.

$o-forms-is-silent: false;
@import 'o-forms/main';


If your project does not need all o-forms features, you may reduce your project's CSS bundle size by using the following mixins to only output what you need.


Optional extras:

For more details on specific mixins browse the SassDoc documentation of the module.


o-forms provides some JavaScript to help with validating form inputs. The validation works with the browsers built-in validation API to add the appropriate o-forms classes when a user is completing or submitting a form.

By default, o-forms listens to the blur event of an input field, when a user leaves a field, the input will be validated and if an invalid input is found, the error class will be added to the input.

Additionally o-forms fires an event oForms.toggled when a toggle checkbox is clicked.

#### Constructing

An o-forms object must be constructed for every <form> element you have on your page that you want to validate with this module. You can do this for explicit elements like so:

const OForms = require('o-forms');
const formsEl = document.querySelector('#form-element');

const forms = new OForms(formsEl);

Alternatively, an o.DOMContentLoaded event can be dispatched on the document to auto-construct an o-forms object for each element with a data-o-component="o-forms" attribute:

document.addEventListener("DOMContentLoaded", function() {
    document.dispatchEvent(new CustomEvent('o.DOMContentLoaded'));

Validate on form submit

By default o-forms tests inputs on the blur event for each input. To defer the validation to the submit event of the form, you can pass an config object to set the testEvent when constructing o-forms:

const OForms = require('o-forms');
const formsEl = document.querySelector('#form-element');

const forms = new OForms(formsEl, { testEvent: 'submit' });

Or you can set an attribute on the <form> element to declaratively set the test event:

<form data-o-component="o-forms" data-o-forms-test-event="submit">

Apply valid state class

By default o-forms does not apply the o-forms--valid class, relying on the absence of o-forms--error to indicate an input's validity. To have o-forms apply a class for valid inputs, pass in a applyValidState boolean configuration property when constructing:

const OForms = require('o-forms');
const formsEl = document.querySelector('#form-element');

const forms = new OForms(formsEl, { applyValidState: true });

Or you can set the data-o-forms-apply-valid-state attribute to true on the <form> element:

<form data-o-component="o-forms" data-o-forms-apply-valid-state="true">

Listening to a toggle change

Listening for the oForms.toggled event we can react to the status of a toggle checkbox. This event is fired when the toggle checkbox is clicked.

document.addEventListener('oForms.toggled', (event) => {
    console.log(`${event.target.id} is ${(event.target.checked ? 'on' : 'off')}`);
}, false);


There are a number of inconsistencies in how browsers handle form events, validation and auto-fill. The Membership team has documented the quirks it ran into during the development of the Sign Up app.

Migration Guide

Upgrading from v4.x.x to v5.x.x

Version 5 makes some design improvements including tightening up the spacing around checkboxes and radio buttons. It also provides many new mixins to make it easier to output o-forms features granularly.

Checkboxes & Radios

Prefix, Suffix


Wrappers and Messages

Other changes

Please contact us if you have any queries.

Upgrading from v3.x.x to v4.x.x

Upgrading from v2.x.x to v3.x.x

The main change in v2 is that classes provided by o-forms now conform more strictly to the BEM naming convention. All form field classes now follow the element convention, so o-forms-text is now o-forms__text.

There is also now a main block class of o-forms which replaces the previous o-forms-group class. Full class changes are below:

An example of the changes should be:

-<div class="o-forms-group">
+<div class="o-forms">

-<label class="o-forms-label"></label>
+<label class="o-forms__label"></label>

-<input type="radio" class="o-forms-radio" />
+<input type="radio" class="o-forms__radio" />

-<input type="checkbox" class="o-forms-checkbox" />
+<input type="checkbox" class="o-forms__checkbox" />

-<input type="text" class="o-forms-text" />
+<input type="text" class="o-forms__text" />

Any modifier classes like o-forms--error have remained the same.

Upgrading from 0.x.x

1. Module name change

o-ft-forms becomes o-forms in v1.

  1. Search o-ft-forms and replace with o-forms
  2. Search oFtForms and replace with oForms

2. Web fonts and icons

In the v0.x.x of o-forms, the module loaded webfonts itself and was setting its own font-family.

The module now inherits the font-family set in your application and doesn't embed web fonts anymore.

Solution: products must load webfonts themselves (tipically, with o-fonts and o-ft-icons).

<!-- Load web fonts and icons with @font-face declarations  -->
<link rel="stylesheet" href="https://www.ft.com/__origami/service/build/v2/bundles/css?modules=o-fonts@^3.0.0,o-icons@^5.0.0" />

<!-- Set the font family on the whole document -->
    html {
        font-family: BentonSans, sans-serif;

3. Helper classes name changes

The most important change is with input elements, that now have their own classes:

-<input type="radio" class="o-ft-forms__field" />
+<input type="radio" class="o-forms-radio" />

-<input type="checkbox" class="o-ft-forms__field" />
+<input type="checkbox" class="o-forms-checkbox" />

-<input type="text" class="o-ft-forms__field" />
+<input type="text" class="o-forms-text" />

o-ft-forms__section is deprecated: sections (previously <fieldset class="o-ft-forms__section">) have to be styled at a product level. Since fieldsets have browser-specific styling issues, prefer <div> elements.

4. Mixins and placeholder classes

If using placeholder classes or extending styles using oFormsClass and oFormsPlaceholderOptionalSelector, use normal selectors, and include the matching mixins, documented in the SassDoc documentation of the module.


If you have any questions or comments about this component, or need help using it, please either raise an issue, visit #ft-origami or email Origami Support.


This software is published by the Financial Times under the MIT licence.

active Origami v1
Switch component view

GitHub Repository

Install o-forms

If using the Build Service, add o-forms@^5.4.0 to your script and link tags.

If running a Manual Build, run npm install "o-forms@^5.4.0".

Help & Support

o-forms is maintained directly by the Origami team. If you have any questions about o-forms or Origami in general, we are happy to help. 😊

Slack: #ft-origami
Email: origami.support@ft.com

Feedback / Issues

To report a bug or request features please create an issue on Github. For support or general feedback please get in touch 😊

Slack: #ft-origami
Email: origami.support@ft.com