formio-sfds
Version:
form.io templates for the SF Design System
278 lines (211 loc) • 10 kB
Markdown
# formio-sfds
This is a [Form.io] theme for the [SF Design System](https://sfdigitalservices.github.io/sf-design-system/).
👉 See [DEVELOP.md](DEVELOP.md#readme) for development documentation.
## Table of contents
* [Usage](#usage)
* [Custom components](#custom-components)
* [Form options](#form-options)
* [Formio.createForm() improvements](#formiocreateform-improvements)
* [Localization](#localization)
* [Icons](#icons)
* [Declarative actions](#declarative-actions)
## Usage
There are a couple of different ways to use this package in your app:
- [Standalone bundle](#standalone-bundle) (**recommended**)
- [UMD bundle](#umd-bundle)
- [CommonJS](#commonjs) (`require()`)
- [CSS](#css)
### Standalone bundle
**This is the recommended import method.** To use the standalone bundle, add a
single script tag to your document after the one for `formio.js`, e.g.
```html
<script src="https://unpkg.com/formiojs/dist/formio.full.min.js"></script>
<script src="https://unpkg.com/formio-sfds/dist/formio-sfds.standalone.js"></script>
```
The standalone bundle does a bunch of things automatically:
1. Inlines the [CSS](#css) in the `<head>`
2. Calls `Formio.use(FormioSFDS)`
2. Patches `Formio.createForm()` so that any form created from then includes
[SFDS-specific enhancements](#formiocreateform-improvements)
### CSS
The CSS in this package provides a suite of styles that target a mix of
Form.io-generated selectors, classes used in the custom theme templates, and a
suite of general-purpose utility classes for tweaking individual elements.
#### Scoped CSS
All of the selectors in the packaged CSS are scoped to (nested in) a
`.formio-sfds` class selector, which effectively prevents them from leaking
into the page where the form is embedded.
Unless you're using the [standalone bundle](#standalone-bundle) (which wraps
the form elements automatically), you'll need to wrap all of your the elements
targeted by `Formio.createForm()` with a `<div class="formio-sfds">`.
### UMD bundle
The UMD bundle exports **only** the Formio theme as `FormioSFDS`, and does not
automatically patch `Formio.createForm()`. This may be your best option if
you're working in an environment with multiple forms on a single page, and/or
other Form.io themes.
First, load both the `formiojs` and `formio-sfds` bundles from your CDN of
choice (e.g. [unpkg]) and link to the CSS:
```html
<script src="https://unpkg.com/formiojs/dist/formio.full.min.js"></script>
<script src="https://unpkg.com/formio-sfds/dist/formio-sfds.umd.js"></script>
<link rel="stylesheet" href="https://unpkg.com/formio-sfds/dist/formio-sfds.css">
```
Then, either in a deferred script or on window `load`, tell Form.io to "use" the SFDS theme:
```js
Formio.use(FormioSFDS)
```
You'll need to do this _before_ you call `Formio.createForm()` to ensure that the templates are registered before the form is built.
### CommonJS
If you're using a CommonJS bundler like webpack, browserify, et al:
1. Install both `formiojs` and `formio-sfds` npm packages:
```
npm install formiojs formio-sfds
```
2. Import in your app:
```js
const { Formio } = require('formiojs')
const FormioSFDS = require('formio-sfds')
Formio.use(FormioSFDS)
```
## Custom components
* `address` fields are rendered as multiple text and number inputs with address
lines (1 and 2), city, state and zip code.
* Fields with type `state` render an HTML `<select>` input with the 50 U.S.
states.
* Fields with type `zip` render a ZIP code input field that validates against a
5-digit number or a ZIP+4 pattern (e.g. `94110-1234`).
## Form options
This theme provides support from additional options by [patching `Formio.createForm()`](#formiocreateform-improvements):
#### `data` option
If provided, the `data` option will be passed along as the form's initial
submission. See also: the [`prefill` option](#prefill-option).
#### `googleTranslate` option
If `googleTranslate` is `false`, the `notranslate` class is added to the
form element wrapper to prevent Google Translate from touching it. This is
preferable (but not required!) when translations are provided via the
`i18n` option, since Google Translate will attempt to translate any element
that _doesn't_ have the `notranslate` class, and may replace a human
translation with a machine translation.
#### `hooks` option
If the `hooks` option is an object, any value that isn't a function is
converted to a [declarative action](#declarative-actions). See formiojs's
[hooks documentation](https://github.com/formio/formio.js/wiki/Form-Renderer#hooks)
for the list of available hooks.
#### `i18n` option
If the `i18n` option is a string, it's treated as a JSON URL from which to
load localizations (translations of form content and field info).
#### `on` option
Like `hooks`, the `on` object can be used to specify [declarative
actions](#declarative-actions) for any of formiojs's
[known form events](https://github.com/formio/formio.js/wiki/Form-Renderer#events).
#### `prefill` option
The `prefill` option allows you to pre-fill form inputs with submission
data:
* The value `querystring` will cause pre-fill values to be parsed from
`window.location.search`. E.g. `?foo=bar` will initialze the form
submission as `{foo: 'bar'}`.
* The value `hash` will cause pre-fill values to be parsed from
`window.location.hash` (afer the leading `#`), so `#foo=bar` will
initialize the form submission as `{foo: 'bar'}`.
* Otherwise, if `prefill` is an instance of [URLSearchParams], the form
submission will be initialized using its entries.
#### `formioSFDSOptOut` option
Setting the `formioSFDSOptOut` option to `true` disables all of the
following customizations for your form:
* Scoped style modifications. **Note:** template modifications can't be
opted out because they're provided at the theme level, so you'll need to
style the selectors generated by [this theme's template](src/templates),
not the built-in ones!
* Select components will not be rendered as plain old `<select>` elements
by default, and the `autocomplete` tag will be ignored.
* Custom [event handlers](#on-option) will not be registered.
* The [`prefill` option](#prefill-option) will be ignored.
## `Formio.createForm()` improvements
* Detects the form rendering language (locale) by looking for the closest
element with a `lang` attribute.
* Select components are made to always use the `html5` "widget", which is just
an HTML `<select>` input
* Form elements are wrapped automatically in `<div class="formio-sfds">`, which
allows the element itself to receive styles defined in the [scoped CSS](#scoped-css).
**This behavior can be disabled via the [`formioSFDSOptOut`
option](#formiosfdsoptout-option).**
## Localization
Localization of form field labels and descriptions can be implemented without
having to keep form.io and the English equivalent in sync with string IDs in
the format `{key}_label` (for field labels) and `{key}_description` (for field
descriptions). For example, given this translation spreadsheet:
| String | en | es |
| :--- | :--- | :-- |
| `homeAddress_label` | Home address | Dirección de casa |
...a field with an API key of `homeAddress` will get the spreadsheet
value, _regardless of the label's value in form.io_.
The same rule applies for HTML content components, which can be overridden
using the `{key}_content` string ID.
## Icons
SFDS icons are rendered with a [selector
observer](https://github.com/josh/selector-observer) to inject SVG icons into
any element with a `data-icon` attribute, as in:
```html
<span data-icon="next" aria-label="Next"></span>
```
See [the source](src/icons/index.js) for a full list of possible `data-icon`
attribute values.
## Declarative actions
The `hooks` and `on` options allow you to customize form behaviors using a
limited vocabulary of "declarative" actions. Each key of these objects is
the name of a hook or event, and its value is an object with a single key
that corresponds to one of the following actions:
* `redirect` takes either a URL string or an object with a `url` key and
redirects (by setting `window.location`) to the URL. Submission data
values may be interpolated in the redirect URL as `{key}`, where `key` is
the API key of the form input. For example:
```json
{
"on": {
"submit": {
"redirect": "/confirm?username={username}"
}
}
}
```
* `validateWithService` passes the submission data to an HTTP web service
for validation. The `url` is the URL of the web service, and may contain
form value interpolations (e.g. `{username}` expands to
`form.submission.data.username`), `method` tells it the HTTP verb
(default: `POST`), and `messages` is an optional object containing custom
messages for different types of errors, such as
`{empty: "error message if the response was empty"}`. For instance, you
might wish to validate a username field via an external service that
would respond with an error if the provided username is already taken:
```json
{
"hooks": {
"beforeSubmit": {
"validateWithService": {
"url": "https://some-validation-service.example.com/username/{username}"
}
}
}
}
```
If the web service fails, _or_ if it's successful and the response JSON
has an `errors` or `error` key, those are reported as errors and will
abort `beforeSubmit` hooks.
* `values` validates submissions by comparing the value of the submission
data with each key in the `values` object. For instance, to ensure that
the `foo` form input has a value of `"bar"` before submission:
```json
{
"hooks": {
"beforeSubmit": {
"values": {
"foo": "bar"
}
}
}
}
```
License: [MIT](./LICENSE)
[form.io]: https://form.io
[unpkg]: https://unpkg.com
[URLSearchParams]: https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams