formio-sfds
Version:
The Form.io theme for sf.gov
282 lines (265 loc) • 13.7 kB
HTML
<html lang="en">
<head>
<title>Patches | formio-sfds documentation</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" href="/sfgov/forms.css">
<link rel="stylesheet" href="https://unpkg.com/highlight.js/styles/github.css">
<style type="text/css">
.h-1em { height: 1em ; }
h2,
h3,
h4,
h5,
h6 {
position: relative;
}
main p {
margin: 0;
}
main p + p {
margin-top: 20px;
}
li + li {
margin-top: 5px;
}
table {
margin: 20px 0;
}
th,
td {
padding: 5px;
}
a[aria-hidden="true"] {
position: absolute;
right: 100%;
font-weight: normal;
text-decoration: none;
}
</style>
</head>
<body>
<div class="formio-sfds">
<div class="container p-2">
<h1 class="h3 mb-4">
<a href="/">formio-sfds@10.0.0</a> /
<a href="/docs/">Docs</a> /
Patches
</h1>
<main>
<h2 id="user-content-patches-to-formiojs"><a href="#patches-to-formiojs" aria-hidden="true" tabindex="-1"><span>#</span></a>Patches to formio.js</h2>
<h3 id="user-content-form-options"><a href="#form-options" aria-hidden="true" tabindex="-1"><span>#</span></a>Form options</h3>
<p>Our patched version of <code>Formio.createForm()</code> adds support for the following
options:</p>
<h5 id="user-content-page-option"><a href="#page-option" aria-hidden="true" tabindex="-1"><span>#</span></a><code>page</code> option</h5>
<p>This sets the initial page of the form by its index (position) in the list of
<em>visible</em> pages starting from 1 (the first page, 2 is the second, and so
on). Also note:</p>
<ul>
<li>The <a href="#data-option"><code>data</code> option</a> is applied before <code>page</code>, so if the desired</li>
</ul>
<p>page is conditionally hidden you will need to also provide data that will
satisfy the conditions.</p>
<ul>
<li>The <a href="#data-option"><code>focus</code> option</a> is applied <em>after</em> <code>page</code>, and will override</li>
</ul>
<p>the page selection if the focused component is on a different page.</p>
<h5 id="user-content-focus-option"><a href="#focus-option" aria-hidden="true" tabindex="-1"><span>#</span></a><code>focus</code> option</h5>
<p>This attempts to focus a specific component by its unique "key" once it's
loaded. Use this when testing validations on a specific field, or to scroll to
a specific part of the form. Also note:</p>
<ul>
<li>The <a href="#data-option"><code>data</code> option</a> is applied before <code>focus</code>, so if components</li>
</ul>
<p>(or their pages) are conditionally hidden you may need to pass data that will
satisfy the conditions.</p>
<ul>
<li>The <a href="#data-option"><code>page</code> option</a> is applied before <code>focus</code>, but you shouldn't</li>
</ul>
<p>need to use both because the form will set the initial page automatically in
order to focus the right component.</p>
<h5 id="user-content-data-option"><a href="#data-option" aria-hidden="true" tabindex="-1"><span>#</span></a><code>data</code> option</h5>
<p>If provided, the <code>data</code> option will be passed along as the form's initial
submission. See also: the <a href="#prefill-option"><code>prefill</code> option</a>.</p>
<h5 id="user-content-googletranslate-option"><a href="#googletranslate-option" aria-hidden="true" tabindex="-1"><span>#</span></a><code>googleTranslate</code> option</h5>
<p>If <code>googleTranslate</code> is <code>false</code>, the <code>translate="no"</code> attribute and
<code>notranslate</code> class are 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 <code>i18n</code> option, since Google Translate will
attempt to translate any element that <em>doesn't</em> have the <code>notranslate</code> class,
and may replace a human translation with a machine translation.</p>
<h5 id="user-content-i18n-option"><a href="#i18n-option" aria-hidden="true" tabindex="-1"><span>#</span></a><code>i18n</code> option</h5>
<p>If the <code>i18n</code> option is a string, it's treated as a JSON URL from which to
load localizations (translations of form content and field info). See <a href="./localization/">the
localization docs</a> for more info.</p>
<h5 id="user-content-hooks-option"><a href="#hooks-option" aria-hidden="true" tabindex="-1"><span>#</span></a><code>hooks</code> option</h5>
<p>If the <code>hooks</code> option is an object, any value that isn't a function is
converted to a <a href="#declarative-actions">declarative action</a>. See formiojs's
<a href="https://github.com/formio/formio.js/wiki/Form-Renderer#hooks">hooks documentation</a>
for the list of available hooks.</p>
<h5 id="user-content-on-option"><a href="#on-option" aria-hidden="true" tabindex="-1"><span>#</span></a><code>on</code> option</h5>
<p>Like <code>hooks</code>, the <code>on</code> object can be used to specify <a href="#declarative-actions">declarative
actions</a> for any of formiojs's
<a href="https://github.com/formio/formio.js/wiki/Form-Renderer#events">known form events</a>.</p>
<h5 id="user-content-prefill-option"><a href="#prefill-option" aria-hidden="true" tabindex="-1"><span>#</span></a><code>prefill</code> option</h5>
<p>The <code>prefill</code> option allows you to pre-fill form inputs with submission
data:</p>
<ul>
<li>
<p>The value <code>querystring</code> will cause pre-fill values to be parsed from
<code>window.location.search</code>. E.g. <code>?foo=bar</code> will initialze the form
submission as <code>{foo: 'bar'}</code>.</p>
</li>
<li>
<p>The value <code>hash</code> will cause pre-fill values to be parsed from
<code>window.location.hash</code> (afer the leading <code>#</code>), so <code>#foo=bar</code> will
initialize the form submission as <code>{foo: 'bar'}</code>.</p>
</li>
<li>
<p>Otherwise, if <code>prefill</code> is an instance of <a href="https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams">URLSearchParams</a>, the form
submission will be initialized using its entries.</p>
</li>
</ul>
<h5 id="user-content-formiosfdsoptout-option"><a href="#formiosfdsoptout-option" aria-hidden="true" tabindex="-1"><span>#</span></a><code>formioSFDSOptOut</code> option</h5>
<p>Setting the <code>formioSFDSOptOut</code> option to <code>true</code> disables all of the following
customizations for your form:</p>
<ul>
<li>
<p>Scoped style modifications. <strong>Note:</strong> 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 <a href="src/templates">this theme's templates</a>, not the
built-in ones!</p>
</li>
<li>
<p>Select components will not be rendered as plain old <code><select></code> elements by
default, and the <code>autocomplete</code> tag will be ignored.</p>
</li>
<li>
<p>Custom <a href="#on-option">event handlers</a> will not be registered.</p>
</li>
<li>
<p>The <a href="#prefill-option"><code>prefill</code> option</a> will be ignored.</p>
</li>
</ul>
<h3 id="user-content-form-upgrades"><a href="#form-upgrades" aria-hidden="true" tabindex="-1"><span>#</span></a>Form upgrades</h3>
<p>Unless otherwise noted, all of the upgrades below can be opted out of with the
<a href="#formiosfdsoptout-option"><code>formioSFDSOptOut</code> option</a>.</p>
<ul>
<li>
<p>Detects the form rendering language (locale) by looking for the closest
element with a <code>lang</code> attribute.</p>
</li>
<li>
<p>Select components are made to always use the <code>html5</code> "widget" (an HTML
<code><select></code> element), <em>unless</em> the <code>autocomplete</code> tag also exists on the
component (if <code>component.tags.include('autocomplete')</code>).</p>
</li>
<li>
<p>Form elements are wrapped in <code><div class="formio-sfds"></code>, which allows the
element itself to receive styles defined in the <a href="#scoped-css">scoped CSS</a>.</p>
</li>
<li>
<p>All components get <code>validateOn: 'blur'</code>, which defers validation of fields
until the input is blurred. The default is <code>change</code>, which triggers
validation whenever an input changes, and can trigger disruptive validation
errors while the user is typing.</p>
</li>
</ul>
<h3 id="user-content-declarative-actions"><a href="#declarative-actions" aria-hidden="true" tabindex="-1"><span>#</span></a>Declarative actions</h3>
<p>The <code>hooks</code> and <code>on</code> 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:</p>
<ul>
<li>
<p><code>redirect</code> takes either a URL string or an object with a <code>url</code> key and
redirects (by setting <code>window.location</code>) to the URL. Submission data
values may be interpolated in the redirect URL as <code>{key}</code>, where <code>key</code> is
the API key of the form input. For example:</p>
<pre><code>{
<span>"on"</span>: {
<span>"submit"</span>: {
<span>"redirect"</span>: <span>"/confirm?username={username}"</span>
}
}
}</code></pre>
</li>
<li>
<p><code>validateWithService</code> passes the submission data to an HTTP web service
for validation. The <code>url</code> is the URL of the web service, and may contain
form value interpolations (e.g. <code>{username}</code> expands to
<code>form.submission.data.username</code>), <code>method</code> tells it the HTTP verb
(default: <code>POST</code>), and <code>messages</code> is an optional object containing custom
messages for different types of errors, such as
<code>{empty: "error message if the response was empty"}</code>. 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:</p>
<pre><code>{
<span>"hooks"</span>: {
<span>"beforeSubmit"</span>: {
<span>"validateWithService"</span>: {
<span>"url"</span>: <span>"https://some-validation-service.example.com/username/{username}"</span>
}
}
}
}</code></pre>
<p>If the web service fails, <em>or</em> if it's successful and the response JSON
has an <code>errors</code> or <code>error</code> key, those are reported as errors and will
abort <code>beforeSubmit</code> hooks.</p>
</li>
<li>
<p><code>values</code> validates submissions by comparing the value of the submission
data with each key in the <code>values</code> object. For instance, to ensure that
the <code>foo</code> form input has a value of <code>"bar"</code> before submission:</p>
<pre><code>{
<span>"hooks"</span>: {
<span>"beforeSubmit"</span>: {
<span>"values"</span>: {
<span>"foo"</span>: <span>"bar"</span>
}
}
}
}</code></pre>
</li>
</ul>
<h3 id="user-content-icons"><a href="#icons" aria-hidden="true" tabindex="-1"><span>#</span></a>Icons</h3>
<p>SFDS icons are rendered using <a href="https://github.com/josh/selector-observer">selector observer</a>
to replace the contents of elements with a <code>data-icon</code> attribute with the
corresponding SVG icon at runtime, i.e. turning this:</p>
<pre><code><span><<span>span</span> <span>data-icon</span>=<span>"next"</span> <span>aria-label</span>=<span>"Next"</span>></span><span></<span>span</span>></span></code></pre>
<p>into this:</p>
<pre><code><span><<span>span</span> <span>data-icon</span>=<span>"next"</span> <span>aria-label</span>=<span>"Next"</span>></span>
<span><<span>svg</span> <span>...</span>></span><span></<span>svg</span>></span>
<span></<span>span</span>></span></code></pre>
<p>FontAwesome icons (any element with an <code>fa-*</code> class name) rendered by Formio
have the <code>data-icon</code> attribute icon added, which in turn triggers the SVG icon
insertion described above, turning this:</p>
<pre><code><span><<span>i</span> <span>class</span>=<span>"fa-info some-class"</span>></span><span></<span>i</span>></span></code></pre>
<p>into this:</p>
<pre><code><span><<span>i</span> <span>data-icon</span>=<span>"info"</span> <span>class</span>=<span>"some-class"</span>></span>
<span><<span>svg</span> <span>...</span>></span><span></<span>svg</span>></span>
<span></<span>i</span>></span></code></pre>
<p>See <a href="https://www.figma.com/file/Eyr2mvPBRMkkecBmbkkGogvP/Assets?node-id=38%3A8">icons in Figma</a> and <a href="https://github.com/SFDigitalServices/formio-sfds/tree/main/src/icons/index.js">the source</a> for a full list of
valid <code>data-icon</code> attribute values.</p>
</main>
<div class="bg-grey-1 p-2 round-1 mt-4 d-flex flex-justify-between">
<div class="mr-2">
<a href="https://github.com/SFDigitalServices/formio-sfds/edit/main/docs/patches.md">
Edit this page on GitHub
</a>
</div>
</div>
</div>
</div>
<script src="https://unpkg.com/formiojs@4.14.8/dist/formio.full.min.js"></script>
<script src="/dist/formio-sfds.standalone.js"></script>
<script>
// fix images with height attributes that get
// `height: auto` from drupal.css
for (const img of document.querySelectorAll('img[height]')) {
img.setAttribute('style', `height: ${img.getAttribute('height')}px;`)
}
</script>
</body>
</html>