Custom Forms

Start of documentation content

Forms can be programatically made as children of <Formally>.

This is an alternative to the formBuilderId prop (which loads forms from

Use of children prop

import { Formally, Root, Page, Content, Text, Fieldset } from 'formally';

export const MyForm = () => (
      <Page id="page1">
        <Content id="content1" />
        <Text id="text1" />
        <Fieldset id="fieldset1">
          <Text id="test2" />
      <Page id="page2">
        <Content id="content2" />


  1. There must be one <Root> component inside <Formally>
  2. The only children of <Root> must be <Page>s.
  3. Every component must have a unique id prop (except <Root>).

The children define all the content and fields in the form.

Although children can vary at runtime it's preferable:

  1. Encoding dynamic behaviour in <Conditional> rule, or;
  2. Using <Formally> props (eg, onValidation);

Localisation / Translations

Locales are languages with optional localised variations, such as "New Zealand English", "Australian English", and plain "English".

Formally components can contain multiple locales, represented as an object where the keys are locale ids.

  en: 'Welcome to the form',
  'en-NZ': 'Welcome / Kia ora',
  'en-AU': 'Gidday',
  mi: 'Kia ora',

A page title might use this as,

<Page id="myPage1" titleHtml={{
  'en': 'Welcome to the form',
  'en-NZ': 'Welcome / Kia ora',
  'en-AU': 'Gidday',
  'mi': 'Kia ora',

These locale ids are the same as the lang attribute value in HTML which comes from RFC 5646: Tags for Identifying Languages (aka BCP 47).

After these strings are added the locale must be enabled with the locales prop of <Root> e.g. locales={['en', 'en-NZ', 'en-AU', 'mi']. The order of this list controls the list of languages in the locale picker UI.

If a user has their browser configured with a locale language preference that will be used. If a user's browser doesn't express a preference then the first locale id will be used.

Removing a locale id from locales is a quick way of disabling a locale.


Every Formally component needs an id which is unique within the form.

A run-time exception will be thrown if the component doesn't have an id.

Localisation: HTML or Plaintext

Formally uses a structured naming convention to indicate whether the localised string is HTML or plaintext. If the prop name ends in Html it's HTML, otherwise it's plaintext. There are also TypeScript definitions that indicate whether a prop is LocalisedHtml or LocalisedPlaintext.

The reason for HTML is so that translations can use the full range of accessibility features such as <abbr>. For example,

    en: 'See <abbr title="Mozilla Developer Network">MDN</abbr> for more',

Important: When providing HTML strings it is the responsibility of the developer to ensure these strings are safely sanitised to prevent malicious use such as XSS exploits. Formally does not sanitise HTML given to it.

Further, because arbitrary HTML is allowed it is up to the developer to test their configuration. HTML is a powerful feature that is easy to misuse. For example, an HTML string of 'my label <a href="">a link</a>' when used as <label> content would have multiple clickable areas (clicking the <label> or clicking the link), which is unlikely to be intended. When in doubt, prefer to sanitise HTML as plaintext.