react-declarative-docs / documents /docs_concepts_field-schema.html
tripolskypetr's picture
patch
9375fc1
<!DOCTYPE html><html class="default" lang="en" data-base=".."><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>docs/concepts/field-schema | react-declarative</title><meta name="description" content="Documentation for react-declarative"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../assets/style.css"/><link rel="stylesheet" href="../assets/highlight.css"/><script defer src="../assets/main.js"></script><script async src="../assets/icons.js" id="tsd-icons-script"></script><script async src="../assets/search.js" id="tsd-search-script"></script><script async src="../assets/navigation.js" id="tsd-nav-script"></script><script async src="../assets/hierarchy.js" id="tsd-hierarchy-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><div class="table-cell" id="tsd-search"><div class="field"><label for="tsd-search-field" class="tsd-widget tsd-toolbar-icon search no-caption"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-search"></use></svg></label><input type="text" id="tsd-search-field" aria-label="Search"/></div><div class="field"><div id="tsd-toolbar-links"></div></div><ul class="results"><li class="state loading">Preparing search index...</li><li class="state failure">The search index is not available</li></ul><a href="../index.html" class="title">react-declarative</a></div><div class="table-cell" id="tsd-widgets"><a href="#" class="tsd-widget tsd-toolbar-icon menu no-caption" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-menu"></use></svg></a></div></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb"><li><a href="../modules.html">react-declarative</a></li><li><a href="docs_concepts_field-schema.html">docs/concepts/field-schema</a></li></ul></div><div class="tsd-panel tsd-typography"><a id="field-schema-how-typedfield-defines-your-form" class="tsd-anchor"></a><h1 class="tsd-anchor-link">Field schema: how TypedField[] defines your form<a href="#field-schema-how-typedfield-defines-your-form" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h1><p>Every form in react-declarative is driven by a single JavaScript array: <code>TypedField[]</code>. Instead of writing JSX for each input, you describe what you need as plain objects, and the <code>&lt;One /&gt;</code> component renders the full UI from that description. This means your form logic lives in data you can inspect, transform, and reuse — not scattered across component trees.</p>
<a id="the-shape-of-a-field-object" class="tsd-anchor"></a><h2 class="tsd-anchor-link">The shape of a field object<a href="#the-shape-of-a-field-object" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>Each entry in the <code>fields</code> array is a plain object with a required <code>type</code> property drawn from the <code>FieldType</code> enum. All other properties are optional and depend on the type you choose.</p>
<pre><code class="typescript"><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-2">TypedField</span><span class="hl-1">, </span><span class="hl-2">FieldType</span><span class="hl-1"> } </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">&#39;react-declarative&#39;</span><span class="hl-1">;</span><br/><br/><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-10">fields</span><span class="hl-1">: </span><span class="hl-7">TypedField</span><span class="hl-1">[] = [</span><br/><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">type:</span><span class="hl-1"> </span><span class="hl-2">FieldType</span><span class="hl-1">.</span><span class="hl-2">Text</span><span class="hl-1">, </span><span class="hl-17">// required — determines which widget renders</span><br/><span class="hl-1"> </span><span class="hl-2">name:</span><span class="hl-1"> </span><span class="hl-3">&#39;firstName&#39;</span><span class="hl-1">, </span><span class="hl-17">// maps to the key in your data object</span><br/><span class="hl-1"> </span><span class="hl-2">title:</span><span class="hl-1"> </span><span class="hl-3">&#39;First name&#39;</span><span class="hl-1">, </span><span class="hl-17">// label shown above the input</span><br/><span class="hl-1"> </span><span class="hl-2">description:</span><span class="hl-1"> </span><span class="hl-3">&#39;Your legal first name&#39;</span><span class="hl-1">, </span><span class="hl-17">// helper text shown below</span><br/><span class="hl-1"> </span><span class="hl-2">defaultValue:</span><span class="hl-1"> </span><span class="hl-3">&#39;&#39;</span><span class="hl-1">, </span><span class="hl-17">// value used when handler returns nothing for this key</span><br/><span class="hl-1"> },</span><br/><span class="hl-1">];</span>
</code><button type="button">Copy</button></pre>
<p>The core properties shared by almost every field are:</p>
<table>
<thead>
<tr>
<th>Property</th>
<th>Type</th>
<th>Purpose</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>type</code></td>
<td><code>FieldType</code></td>
<td>Selects the widget or layout to render</td>
</tr>
<tr>
<td><code>name</code></td>
<td><code>string</code></td>
<td>Maps the field to a key in your data object</td>
</tr>
<tr>
<td><code>title</code></td>
<td><code>string</code></td>
<td>Label displayed with the field</td>
</tr>
<tr>
<td><code>description</code></td>
<td><code>string</code></td>
<td>Helper text shown below the input</td>
</tr>
<tr>
<td><code>defaultValue</code></td>
<td><code>Value | ((payload) =&gt; Value)</code></td>
<td>Initial value when the data object has no entry for this key</td>
</tr>
<tr>
<td><code>columns</code></td>
<td><code>string</code></td>
<td>Column span (out of 12) at all breakpoints</td>
</tr>
<tr>
<td><code>phoneColumns</code></td>
<td><code>string</code></td>
<td>Column span on phone-sized screens</td>
</tr>
<tr>
<td><code>tabletColumns</code></td>
<td><code>string</code></td>
<td>Column span on tablet-sized screens</td>
</tr>
<tr>
<td><code>desktopColumns</code></td>
<td><code>string</code></td>
<td>Column span on desktop-sized screens</td>
</tr>
</tbody>
</table>
<a id="how-name-maps-to-your-data" class="tsd-anchor"></a><h2 class="tsd-anchor-link">How <code>name</code> maps to your data<a href="#how-name-maps-to-your-data" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>The <code>name</code> property is the bridge between a field and your data object. When <code>&lt;One /&gt;</code> reads the initial data from your <code>handler</code>, it looks up <code>data[field.name]</code> to populate each input. When the user changes a value, <code>onChange</code> receives a new data object with <code>data[field.name]</code> updated.</p>
<pre><code class="typescript"><span class="hl-17">// This field schema...</span><br/><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-10">fields</span><span class="hl-1">: </span><span class="hl-7">TypedField</span><span class="hl-1">[] = [</span><br/><span class="hl-1"> { </span><span class="hl-2">type:</span><span class="hl-1"> </span><span class="hl-2">FieldType</span><span class="hl-1">.</span><span class="hl-2">Text</span><span class="hl-1">, </span><span class="hl-2">name:</span><span class="hl-1"> </span><span class="hl-3">&#39;email&#39;</span><span class="hl-1"> },</span><br/><span class="hl-1"> { </span><span class="hl-2">type:</span><span class="hl-1"> </span><span class="hl-2">FieldType</span><span class="hl-1">.</span><span class="hl-2">Text</span><span class="hl-1">, </span><span class="hl-2">name:</span><span class="hl-1"> </span><span class="hl-3">&#39;phone&#39;</span><span class="hl-1"> },</span><br/><span class="hl-1">];</span><br/><br/><span class="hl-17">// ...reads from and writes to objects shaped like this:</span><br/><span class="hl-4">interface</span><span class="hl-1"> </span><span class="hl-7">FormData</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">email</span><span class="hl-1">: </span><span class="hl-7">string</span><span class="hl-1">;</span><br/><span class="hl-1"> </span><span class="hl-2">phone</span><span class="hl-1">: </span><span class="hl-7">string</span><span class="hl-1">;</span><br/><span class="hl-1">}</span>
</code><button type="button">Copy</button></pre>
<p>Layout types such as <code>FieldType.Group</code>, <code>FieldType.Paper</code>, and <code>FieldType.Expansion</code> do not need a <code>name</code> because they are containers — they wrap other fields but do not store values themselves.</p>
<a id="nesting-fields-inside-a-group" class="tsd-anchor"></a><h2 class="tsd-anchor-link">Nesting fields inside a group<a href="#nesting-fields-inside-a-group" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>Layout fields accept a <code>fields</code> array (or a single <code>child</code>) that contains the fields to render inside them. The most common layout is <code>FieldType.Group</code>, which arranges its children in a responsive grid.</p>
<pre><code class="typescript"><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-10">fields</span><span class="hl-1">: </span><span class="hl-7">TypedField</span><span class="hl-1">[] = [</span><br/><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">type:</span><span class="hl-1"> </span><span class="hl-2">FieldType</span><span class="hl-1">.</span><span class="hl-2">Group</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">phoneColumns:</span><span class="hl-1"> </span><span class="hl-3">&#39;12&#39;</span><span class="hl-1">, </span><span class="hl-17">// full width on phones</span><br/><span class="hl-1"> </span><span class="hl-2">tabletColumns:</span><span class="hl-1"> </span><span class="hl-3">&#39;6&#39;</span><span class="hl-1">, </span><span class="hl-17">// half width on tablets</span><br/><span class="hl-1"> </span><span class="hl-2">desktopColumns:</span><span class="hl-1"> </span><span class="hl-3">&#39;4&#39;</span><span class="hl-1">, </span><span class="hl-17">// one-third width on desktops</span><br/><span class="hl-1"> </span><span class="hl-2">fields:</span><span class="hl-1"> [</span><br/><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">type:</span><span class="hl-1"> </span><span class="hl-2">FieldType</span><span class="hl-1">.</span><span class="hl-2">Text</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">name:</span><span class="hl-1"> </span><span class="hl-3">&#39;firstName&#39;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">title:</span><span class="hl-1"> </span><span class="hl-3">&#39;First name&#39;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">defaultValue:</span><span class="hl-1"> </span><span class="hl-3">&#39;Jane&#39;</span><span class="hl-1">,</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">type:</span><span class="hl-1"> </span><span class="hl-2">FieldType</span><span class="hl-1">.</span><span class="hl-2">Text</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">name:</span><span class="hl-1"> </span><span class="hl-3">&#39;lastName&#39;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">title:</span><span class="hl-1"> </span><span class="hl-3">&#39;Last name&#39;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">defaultValue:</span><span class="hl-1"> </span><span class="hl-3">&#39;Smith&#39;</span><span class="hl-1">,</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> ],</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">type:</span><span class="hl-1"> </span><span class="hl-2">FieldType</span><span class="hl-1">.</span><span class="hl-2">Text</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">name:</span><span class="hl-1"> </span><span class="hl-3">&#39;bio&#39;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">title:</span><span class="hl-1"> </span><span class="hl-3">&#39;Short bio&#39;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">inputRows:</span><span class="hl-1"> </span><span class="hl-16">3</span><span class="hl-1">, </span><span class="hl-17">// renders as a multiline textarea</span><br/><span class="hl-1"> },</span><br/><span class="hl-1">];</span>
</code><button type="button">Copy</button></pre>
<a id="the-12-column-responsive-grid" class="tsd-anchor"></a><h2 class="tsd-anchor-link">The 12-column responsive grid<a href="#the-12-column-responsive-grid" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>react-declarative uses a 12-column grid system. The <code>columns</code>, <code>phoneColumns</code>, <code>tabletColumns</code>, and <code>desktopColumns</code> properties all accept a string that represents how many of the 12 columns the element should occupy.</p>
<blockquote>
<p><strong>Note:</strong> If you set only <code>columns</code>, the other three breakpoints inherit its value. Set the per-breakpoint variants only when you need different behaviour at specific screen sizes.</p>
</blockquote>
<pre><code class="typescript"><span class="hl-17">// Full width on every screen</span><br/><span class="hl-1">{ </span><span class="hl-20">type</span><span class="hl-1">: </span><span class="hl-2">FieldType</span><span class="hl-1">.</span><span class="hl-2">Text</span><span class="hl-1">, </span><span class="hl-20">name</span><span class="hl-1">: </span><span class="hl-3">&#39;bio&#39;</span><span class="hl-1">, </span><span class="hl-20">columns</span><span class="hl-1">: </span><span class="hl-3">&#39;12&#39;</span><span class="hl-1"> }</span><br/><br/><span class="hl-17">// Responsive: stacks on mobile, side-by-side on larger screens</span><br/><span class="hl-1">{ </span><span class="hl-20">type</span><span class="hl-1">: </span><span class="hl-2">FieldType</span><span class="hl-1">.</span><span class="hl-2">Text</span><span class="hl-1">, </span><span class="hl-20">name</span><span class="hl-1">: </span><span class="hl-3">&#39;firstName&#39;</span><span class="hl-1">, </span><span class="hl-20">phoneColumns</span><span class="hl-1">: </span><span class="hl-3">&#39;12&#39;</span><span class="hl-1">, </span><span class="hl-20">tabletColumns</span><span class="hl-1">: </span><span class="hl-3">&#39;6&#39;</span><span class="hl-1">, </span><span class="hl-20">desktopColumns</span><span class="hl-1">: </span><span class="hl-3">&#39;4&#39;</span><span class="hl-1"> }</span><br/><span class="hl-1">{ </span><span class="hl-20">type</span><span class="hl-1">: </span><span class="hl-2">FieldType</span><span class="hl-1">.</span><span class="hl-2">Text</span><span class="hl-1">, </span><span class="hl-20">name</span><span class="hl-1">: </span><span class="hl-3">&#39;lastName&#39;</span><span class="hl-1">, </span><span class="hl-20">phoneColumns</span><span class="hl-1">: </span><span class="hl-3">&#39;12&#39;</span><span class="hl-1">, </span><span class="hl-20">tabletColumns</span><span class="hl-1">: </span><span class="hl-3">&#39;6&#39;</span><span class="hl-1">, </span><span class="hl-20">desktopColumns</span><span class="hl-1">: </span><span class="hl-3">&#39;4&#39;</span><span class="hl-1"> }</span>
</code><button type="button">Copy</button></pre>
<a id="typescript-generics-typedfield" class="tsd-anchor"></a><h2 class="tsd-anchor-link">TypeScript generics: TypedField&lt;Data, Payload&gt;<a href="#typescript-generics-typedfield" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p><code>TypedField</code> accepts two generic parameters that flow through every callback in the schema:</p>
<ul>
<li><strong><code>Data</code></strong> — the shape of your form's data object. Typed callbacks like <code>isInvalid</code>, <code>isVisible</code>, and <code>compute</code> receive a <code>Data</code> value, so TypeScript can tell you exactly which keys exist.</li>
<li><strong><code>Payload</code></strong> — an extra context object you pass into <code>&lt;One /&gt;</code> via the <code>payload</code> prop (for example, a user role or feature flags). Callbacks also receive <code>Payload</code>.</li>
</ul>
<pre><code class="typescript"><span class="hl-4">interface</span><span class="hl-1"> </span><span class="hl-7">ProfileData</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">email</span><span class="hl-1">: </span><span class="hl-7">string</span><span class="hl-1">;</span><br/><span class="hl-1"> </span><span class="hl-2">role</span><span class="hl-1">: </span><span class="hl-3">&#39;admin&#39;</span><span class="hl-1"> | </span><span class="hl-3">&#39;user&#39;</span><span class="hl-1">;</span><br/><span class="hl-1">}</span><br/><br/><span class="hl-4">interface</span><span class="hl-1"> </span><span class="hl-7">AppPayload</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">currentUserId</span><span class="hl-1">: </span><span class="hl-7">string</span><span class="hl-1">;</span><br/><span class="hl-1">}</span><br/><br/><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-10">fields</span><span class="hl-1">: </span><span class="hl-7">TypedField</span><span class="hl-1">&lt;</span><span class="hl-7">ProfileData</span><span class="hl-1">, </span><span class="hl-7">AppPayload</span><span class="hl-1">&gt;[] = [</span><br/><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">type:</span><span class="hl-1"> </span><span class="hl-2">FieldType</span><span class="hl-1">.</span><span class="hl-2">Text</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">name:</span><span class="hl-1"> </span><span class="hl-3">&#39;email&#39;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">title:</span><span class="hl-1"> </span><span class="hl-3">&#39;Email&#39;</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">isInvalid</span><span class="hl-1">(</span><span class="hl-2">data</span><span class="hl-1">, </span><span class="hl-2">payload</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-17">// data is typed as ProfileData — full autocomplete</span><br/><span class="hl-1"> </span><span class="hl-17">// payload is typed as AppPayload</span><br/><span class="hl-1"> </span><span class="hl-0">if</span><span class="hl-1"> (!</span><span class="hl-2">data</span><span class="hl-1">.</span><span class="hl-2">email</span><span class="hl-1">.</span><span class="hl-5">includes</span><span class="hl-1">(</span><span class="hl-3">&#39;@&#39;</span><span class="hl-1">)) </span><span class="hl-0">return</span><span class="hl-1"> </span><span class="hl-3">&#39;Invalid email&#39;</span><span class="hl-1">;</span><br/><span class="hl-1"> </span><span class="hl-0">return</span><span class="hl-1"> </span><span class="hl-4">null</span><span class="hl-1">;</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> },</span><br/><span class="hl-1">];</span>
</code><button type="button">Copy</button></pre>
<blockquote>
<p><strong>Tip:</strong> Start with <code>TypedField[]</code> (no generics) while exploring. Add the generics once you know the shape of your data — TypeScript will then catch mismatches in every field callback.</p>
</blockquote>
</div></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><h3><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-external" name="external"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>External</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div><details open class="tsd-accordion tsd-page-navigation"><summary class="tsd-accordion-summary"><h3><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg>On This Page</h3></summary><div class="tsd-accordion-details"><a href="#field-schema-how-typedfield-defines-your-form"><span>Field schema: how <wbr/>Typed<wbr/>Field[] defines your form</span></a><ul><li><a href="#the-shape-of-a-field-object"><span>The shape of a field object</span></a></li><li><a href="#how-name-maps-to-your-data"><span>How name maps to your data</span></a></li><li><a href="#nesting-fields-inside-a-group"><span>Nesting fields inside a group</span></a></li><li><a href="#the-12-column-responsive-grid"><span>The 12-<wbr/>column responsive grid</span></a></li><li><a href="#typescript-generics-typedfield"><span>Type<wbr/>Script generics: <wbr/>Typed<wbr/>Field&lt;<wbr/>Data, <wbr/>Payload&gt;</span></a></li></ul></div></details></div><div class="site-menu"><nav class="tsd-navigation"><a href="../modules.html">react-declarative</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html>