Custom Forms

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

This is an alternative to the formBuilderId prop (which loads forms from GetFormally.com).

Use of children prop

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

export const MyForm = () => (
  <Formally>
    <Root>
      <Page>
        <Content />
        <Text />
        <Fieldset>
          <Text />
        </Fieldset>
      </Page>
      <Page>
        <Content />
      </Page>
    </Root>
  </Formally>
);

Note: the props of <Root>, <Page>, <Content>, <Fieldset>, and <Text> have been ommited for brevity in this example as it's trying to show the overall form structure.

Rules

  1. There must be one <Root> component inside <Formally>
  2. The only children of <Root> must be <Page>s.

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

Although children can vary at runtime instead dynamic behaviour should be done by:

  1. Encoding dynamic behaviour such as conditional logic in the data, or;
  2. Using props (eg, onValidation in <Formally onValidation={myCustomValidation}) />);

Creating children

Use these components exported from formally:

  • <Root>
  • <Page>
  • <Text>
  • <DateInput>
  • <Range>
  • <AutoSuggest>
  • <Radios>
  • <Checkboxes>
  • <Select>
  • <Upload>
  • <Conditional>
  • <Repeater>
  • <Fieldset>
  • <Content>
  • <AnswerSummary>
  • <PopOutContent>
  • <CustomField>
  • <OptionRoot>
  • <OptionGroup>
  • <Option>

Be sure to read the relevant documentation page to do with each component.

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 form title might use this as,

<Root 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.

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 e.g. a label

<Text
  hintHtml={{
    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.

Ids

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

When using the Form Builder it's usually not necessary to think about component ids (they're autogenerated), however when using the SDK it becomes necessary.

When Formally components are under <Formally> then an id is autogenerated and developers don't need to provide this prop, however if Formally components are included from other components, ie in this situation:

export default () => (
  <Formally>
    <Range />
    <MyWrapper />
  </Formally>
);

const MyWrapper = () => <Text />;

The <Range /> wouldn't need an id prop but the <Text> would.

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

Stable Ids

It's always possible to provide an id prop, and this is referred to as a 'stable id' because it's not randomly autogenerated.

Some features of Formally refer to other components by id and a stable id should be used.

For example, a <Conditional> (which conditionally displays components) might have a rule referring to a <Text> by id.