react-declarative-docs / documents /docs_guides_custom-fields.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/guides/custom-fields | 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_guides_custom-fields.html">docs/guides/custom-fields</a></li></ul></div><div class="tsd-panel tsd-typography"><a id="custom-fields-component-injection-and-slotfactory" class="tsd-anchor"></a><h1 class="tsd-anchor-link">Custom fields: Component injection and SlotFactory<a href="#custom-fields-component-injection-and-slotfactory" 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>React-declarative gives you two complementary ways to customize what renders inside a form. <code>FieldType.Component</code> lets you drop any React component into a specific slot in your schema — a one-off injection with full access to the current form data. <code>OneSlotFactory</code> lets you replace a built-in field renderer globally, so every <code>FieldType.Text</code> (or any other type) across your entire application uses your custom component instead.</p>
<a id="injecting-jsx-with-fieldtypecomponent" class="tsd-anchor"></a><h2 class="tsd-anchor-link">Injecting JSX with <code>FieldType.Component</code><a href="#injecting-jsx-with-fieldtypecomponent" 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>Add a <code>FieldType.Component</code> entry to your fields array and provide an <code>element</code> function that returns a React component. The component receives a <code>ComponentFieldInstance</code> object as its props.</p>
<pre><code class="tsx"><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-2">FieldType</span><span class="hl-1">, </span><span class="hl-2">TypedField</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">Paper</span><span class="hl-1">,</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">Component</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">element</span><span class="hl-2">:</span><span class="hl-1"> (</span><span class="hl-2">props</span><span class="hl-1">) </span><span class="hl-4">=&gt;</span><span class="hl-1"> </span><span class="hl-6">&lt;</span><span class="hl-7">Logger</span><span class="hl-1"> </span><span class="hl-4">{</span><span class="hl-1">...</span><span class="hl-2">props</span><span class="hl-4">}</span><span class="hl-1"> </span><span class="hl-6">/&gt;</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>
</code><button type="button">Copy</button></pre>
<a id="props-available-inside-element" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Props available inside <code>element</code><a href="#props-available-inside-element" 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></h3><p>The component you supply receives the full field instance props. The most commonly used ones are:</p>
<table>
<thead>
<tr>
<th>Prop</th>
<th>Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>data</code></td>
<td><code>Data</code></td>
<td>The current form data object</td>
</tr>
<tr>
<td><code>payload</code></td>
<td><code>Payload</code></td>
<td>The external payload passed to <code>&lt;One /&gt;</code></td>
</tr>
<tr>
<td><code>onChange</code></td>
<td><code>(data: Partial&lt;Data&gt;) =&gt; void</code></td>
<td>Merge partial data back into the form</td>
</tr>
<tr>
<td><code>name</code></td>
<td><code>string</code></td>
<td>The <code>name</code> property from the field schema</td>
</tr>
<tr>
<td><code>invalid</code></td>
<td><code>string | null</code></td>
<td>Current validation error message</td>
</tr>
<tr>
<td><code>disabled</code></td>
<td><code>boolean</code></td>
<td>Whether the field is disabled</td>
</tr>
<tr>
<td><code>readonly</code></td>
<td><code>boolean</code></td>
<td>Whether the field is read-only</td>
</tr>
</tbody>
</table>
<pre><code class="tsx"><span class="hl-4">interface</span><span class="hl-1"> </span><span class="hl-7">IStatusBadgeProps</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">data</span><span class="hl-1">: { </span><span class="hl-2">status</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">payload</span><span class="hl-1">: { </span><span class="hl-2">theme</span><span class="hl-1">: </span><span class="hl-3">&#39;light&#39;</span><span class="hl-1"> | </span><span class="hl-3">&#39;dark&#39;</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-5">StatusBadge</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><span class="hl-7">IStatusBadgeProps</span><span class="hl-1">) </span><span class="hl-4">=&gt;</span><span class="hl-1"> (</span><br/><span class="hl-1"> </span><span class="hl-6">&lt;</span><span class="hl-18">span</span><br/><span class="hl-1"> </span><span class="hl-8">style</span><span class="hl-1">=</span><span class="hl-4">{</span><span class="hl-9">{</span><br/><span class="hl-9"> </span><span class="hl-2">color:</span><span class="hl-9"> </span><span class="hl-2">data</span><span class="hl-9">.</span><span class="hl-2">status</span><span class="hl-9"> </span><span class="hl-1">===</span><span class="hl-9"> </span><span class="hl-3">&#39;active&#39;</span><span class="hl-9"> </span><span class="hl-1">?</span><span class="hl-9"> </span><span class="hl-3">&#39;green&#39;</span><span class="hl-9"> </span><span class="hl-1">:</span><span class="hl-9"> </span><span class="hl-3">&#39;red&#39;</span><span class="hl-9">,</span><br/><span class="hl-9"> </span><span class="hl-2">background:</span><span class="hl-9"> </span><span class="hl-2">payload</span><span class="hl-9">.</span><span class="hl-2">theme</span><span class="hl-9"> </span><span class="hl-1">===</span><span class="hl-9"> </span><span class="hl-3">&#39;dark&#39;</span><span class="hl-9"> </span><span class="hl-1">?</span><span class="hl-9"> </span><span class="hl-3">&#39;#333&#39;</span><span class="hl-9"> </span><span class="hl-1">:</span><span class="hl-9"> </span><span class="hl-3">&#39;#eee&#39;</span><span class="hl-9">,</span><br/><span class="hl-9"> }</span><span class="hl-4">}</span><br/><span class="hl-1"> </span><span class="hl-6">&gt;</span><br/><span class="hl-1"> </span><span class="hl-4">{</span><span class="hl-2">data</span><span class="hl-9">.</span><span class="hl-2">status</span><span class="hl-4">}</span><br/><span class="hl-1"> </span><span class="hl-6">&lt;/</span><span class="hl-18">span</span><span class="hl-6">&gt;</span><br/><span class="hl-1">);</span><br/><br/><span class="hl-17">// In your schema:</span><br/><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">Component</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-20">element</span><span class="hl-1">: (</span><span class="hl-2">props</span><span class="hl-1">) </span><span class="hl-4">=&gt;</span><span class="hl-1"> </span><span class="hl-6">&lt;</span><span class="hl-7">StatusBadge</span><span class="hl-1"> </span><span class="hl-4">{</span><span class="hl-1">...</span><span class="hl-2">props</span><span class="hl-4">}</span><span class="hl-1"> </span><span class="hl-6">/&gt;</span><span class="hl-1">,</span><br/><span class="hl-1">}</span>
</code><button type="button">Copy</button></pre>
<blockquote>
<p><strong>Note:</strong> The <code>element</code> function is called on every render. Keep it a thin wrapper —
put your real logic inside the component you reference, not inside <code>element</code>
itself.</p>
</blockquote>
<a id="writing-back-to-the-form" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Writing back to the form<a href="#writing-back-to-the-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></h3><p>Call <code>onChange</code> with a partial data object to update specific fields:</p>
<pre><code class="tsx"><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-5">PrefillButton</span><span class="hl-1"> = ({ </span><span class="hl-2">onChange</span><span class="hl-1"> }: { </span><span class="hl-5">onChange</span><span class="hl-1">: (</span><span class="hl-2">d</span><span class="hl-1">: </span><span class="hl-7">any</span><span class="hl-1">) </span><span class="hl-4">=&gt;</span><span class="hl-1"> </span><span class="hl-7">void</span><span class="hl-1"> }) </span><span class="hl-4">=&gt;</span><span class="hl-1"> (</span><br/><span class="hl-1"> </span><span class="hl-6">&lt;</span><span class="hl-18">button</span><br/><span class="hl-1"> </span><span class="hl-8">onClick</span><span class="hl-1">=</span><span class="hl-4">{</span><span class="hl-9">() </span><span class="hl-4">=&gt;</span><br/><span class="hl-9"> </span><span class="hl-5">onChange</span><span class="hl-9">({ </span><span class="hl-2">firstName:</span><span class="hl-9"> </span><span class="hl-3">&#39;Jane&#39;</span><span class="hl-9">, </span><span class="hl-2">lastName:</span><span class="hl-9"> </span><span class="hl-3">&#39;Smith&#39;</span><span class="hl-9"> })</span><br/><span class="hl-9"> </span><span class="hl-4">}</span><br/><span class="hl-1"> </span><span class="hl-6">&gt;</span><br/><span class="hl-1"> Prefill demo data</span><br/><span class="hl-1"> </span><span class="hl-6">&lt;/</span><span class="hl-18">button</span><span class="hl-6">&gt;</span><br/><span class="hl-1">);</span><br/><br/><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">Component</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-20">element</span><span class="hl-1">: (</span><span class="hl-2">props</span><span class="hl-1">) </span><span class="hl-4">=&gt;</span><span class="hl-1"> </span><span class="hl-6">&lt;</span><span class="hl-7">PrefillButton</span><span class="hl-1"> </span><span class="hl-8">onChange</span><span class="hl-1">=</span><span class="hl-4">{</span><span class="hl-2">props</span><span class="hl-9">.</span><span class="hl-2">onChange</span><span class="hl-4">}</span><span class="hl-1"> </span><span class="hl-6">/&gt;</span><span class="hl-1">,</span><br/><span class="hl-1">}</span>
</code><button type="button">Copy</button></pre>
<a id="replacing-built-in-renderers-with-oneslotfactory" class="tsd-anchor"></a><h2 class="tsd-anchor-link">Replacing built-in renderers with <code>OneSlotFactory</code><a href="#replacing-built-in-renderers-with-oneslotfactory" 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>OneSlotFactory</code> is a React context provider that accepts replacement components for any built-in field type. Wrap your <code>&lt;One /&gt;</code> component (or your entire application) in <code>&lt;OneSlotFactory&gt;</code> to apply overrides everywhere inside it.</p>
<pre><code class="tsx"><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-2">OneSlotFactory</span><span class="hl-1">, </span><span class="hl-2">One</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/><span class="hl-0">import</span><span class="hl-1"> </span><span class="hl-2">MyInput</span><span class="hl-1"> </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">&#39;./MyInput&#39;</span><span class="hl-1">;</span><br/><span class="hl-0">import</span><span class="hl-1"> </span><span class="hl-2">MyCheckBox</span><span class="hl-1"> </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">&#39;./MyCheckBox&#39;</span><span class="hl-1">;</span><br/><br/><span class="hl-4">const</span><span class="hl-1"> </span><span class="hl-5">App</span><span class="hl-1"> = () </span><span class="hl-4">=&gt;</span><span class="hl-1"> (</span><br/><span class="hl-1"> </span><span class="hl-6">&lt;</span><span class="hl-7">OneSlotFactory</span><br/><span class="hl-1"> </span><span class="hl-8">Text</span><span class="hl-1">=</span><span class="hl-4">{</span><span class="hl-2">MyInput</span><span class="hl-4">}</span><br/><span class="hl-1"> </span><span class="hl-8">CheckBox</span><span class="hl-1">=</span><span class="hl-4">{</span><span class="hl-2">MyCheckBox</span><span class="hl-4">}</span><br/><span class="hl-1"> </span><span class="hl-6">&gt;</span><br/><span class="hl-1"> </span><span class="hl-6">&lt;</span><span class="hl-7">One</span><span class="hl-1"> </span><span class="hl-8">fields</span><span class="hl-1">=</span><span class="hl-4">{</span><span class="hl-2">fields</span><span class="hl-4">}</span><span class="hl-1"> </span><span class="hl-8">handler</span><span class="hl-1">=</span><span class="hl-4">{</span><span class="hl-2">handler</span><span class="hl-4">}</span><span class="hl-1"> </span><span class="hl-6">/&gt;</span><br/><span class="hl-1"> </span><span class="hl-6">&lt;/</span><span class="hl-7">OneSlotFactory</span><span class="hl-6">&gt;</span><br/><span class="hl-1">);</span>
</code><button type="button">Copy</button></pre>
<p>Every <code>FieldType.Text</code> and <code>FieldType.Checkbox</code> field inside the provider now uses your components.</p>
<a id="available-slot-names" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Available slot names<a href="#available-slot-names" 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></h3><p>The following slot names correspond to <code>FieldType</code> values you can override:</p>
<p><strong>Input slots</strong></p>
<p><code>Text</code>, <code>Date</code>, <code>Time</code>, <code>Slider</code>, <code>Rating</code>, <code>Progress</code></p>
<p><strong>Selection slots</strong></p>
<p><code>CheckBox</code>, <code>Switch</code>, <code>YesNo</code>, <code>Radio</code>, <code>Combo</code>, <code>Items</code>, <code>Complete</code>, <code>Tree</code>, <code>Dict</code>, <code>Choose</code></p>
<p><strong>Action slots</strong></p>
<p><code>Button</code>, <code>Icon</code></p>
<p><strong>Layout and display slots</strong></p>
<p><code>Line</code>, <code>Typography</code>, <code>File</code></p>
<a id="slot-component-props" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Slot component props<a href="#slot-component-props" 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></h3><p>Each slot component receives a typed props interface. For example, a custom <code>Text</code> component receives <code>ITextSlot</code>, a custom <code>CheckBox</code> component receives <code>ICheckBoxSlot</code>. These interfaces are exported from <code>react-declarative</code>:</p>
<pre><code class="tsx"><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-2">ITextSlot</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-5">MyInput</span><span class="hl-1"> = ({ </span><span class="hl-2">value</span><span class="hl-1">, </span><span class="hl-2">onChange</span><span class="hl-1">, </span><span class="hl-2">disabled</span><span class="hl-1">, </span><span class="hl-2">readonly</span><span class="hl-1">, </span><span class="hl-2">title</span><span class="hl-1">, </span><span class="hl-2">description</span><span class="hl-1">, </span><span class="hl-2">invalid</span><span class="hl-1"> }: </span><span class="hl-7">ITextSlot</span><span class="hl-1">) </span><span class="hl-4">=&gt;</span><span class="hl-1"> (</span><br/><span class="hl-1"> </span><span class="hl-6">&lt;</span><span class="hl-18">div</span><span class="hl-1"> </span><span class="hl-8">className</span><span class="hl-1">=</span><span class="hl-3">&quot;my-input-wrapper&quot;</span><span class="hl-6">&gt;</span><br/><span class="hl-1"> </span><span class="hl-6">&lt;</span><span class="hl-18">label</span><span class="hl-6">&gt;</span><span class="hl-4">{</span><span class="hl-2">title</span><span class="hl-4">}</span><span class="hl-6">&lt;/</span><span class="hl-18">label</span><span class="hl-6">&gt;</span><br/><span class="hl-1"> </span><span class="hl-6">&lt;</span><span class="hl-18">input</span><br/><span class="hl-1"> </span><span class="hl-8">value</span><span class="hl-1">=</span><span class="hl-4">{</span><span class="hl-2">value</span><span class="hl-9"> </span><span class="hl-1">??</span><span class="hl-9"> </span><span class="hl-3">&#39;&#39;</span><span class="hl-4">}</span><br/><span class="hl-1"> </span><span class="hl-8">disabled</span><span class="hl-1">=</span><span class="hl-4">{</span><span class="hl-2">disabled</span><span class="hl-4">}</span><br/><span class="hl-1"> </span><span class="hl-8">readOnly</span><span class="hl-1">=</span><span class="hl-4">{</span><span class="hl-2">readonly</span><span class="hl-4">}</span><br/><span class="hl-1"> </span><span class="hl-8">onChange</span><span class="hl-1">=</span><span class="hl-4">{</span><span class="hl-9">(</span><span class="hl-2">e</span><span class="hl-9">) </span><span class="hl-4">=&gt;</span><span class="hl-9"> </span><span class="hl-5">onChange</span><span class="hl-9">(</span><span class="hl-2">e</span><span class="hl-9">.</span><span class="hl-2">target</span><span class="hl-9">.</span><span class="hl-2">value</span><span class="hl-9">)</span><span class="hl-4">}</span><br/><span class="hl-1"> </span><span class="hl-8">aria-invalid</span><span class="hl-1">=</span><span class="hl-4">{</span><span class="hl-1">!!</span><span class="hl-2">invalid</span><span class="hl-4">}</span><br/><span class="hl-1"> </span><span class="hl-6">/&gt;</span><br/><span class="hl-1"> </span><span class="hl-4">{</span><span class="hl-2">invalid</span><span class="hl-9"> </span><span class="hl-1">&amp;&amp;</span><span class="hl-9"> </span><span class="hl-6">&lt;</span><span class="hl-18">span</span><span class="hl-9"> </span><span class="hl-8">className</span><span class="hl-1">=</span><span class="hl-3">&quot;error&quot;</span><span class="hl-6">&gt;</span><span class="hl-4">{</span><span class="hl-2">invalid</span><span class="hl-4">}</span><span class="hl-6">&lt;/</span><span class="hl-18">span</span><span class="hl-6">&gt;</span><span class="hl-4">}</span><br/><span class="hl-1"> </span><span class="hl-4">{</span><span class="hl-2">description</span><span class="hl-9"> </span><span class="hl-1">&amp;&amp;</span><span class="hl-9"> </span><span class="hl-6">&lt;</span><span class="hl-18">small</span><span class="hl-6">&gt;</span><span class="hl-4">{</span><span class="hl-2">description</span><span class="hl-4">}</span><span class="hl-6">&lt;/</span><span class="hl-18">small</span><span class="hl-6">&gt;</span><span class="hl-4">}</span><br/><span class="hl-1"> </span><span class="hl-6">&lt;/</span><span class="hl-18">div</span><span class="hl-6">&gt;</span><br/><span class="hl-1">);</span>
</code><button type="button">Copy</button></pre>
<a id="when-to-use-component-vs-oneslotfactory" class="tsd-anchor"></a><h2 class="tsd-anchor-link">When to use <code>Component</code> vs <code>OneSlotFactory</code><a href="#when-to-use-component-vs-oneslotfactory" 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><strong>Use FieldType.Component when...</strong></p>
<ul>
<li>You need a one-off widget that is unique to a single form or single place in a schema</li>
<li>You want to display custom read-only data visualizations (charts, status badges, progress indicators)</li>
<li>You need a component that writes back partial data updates via <code>onChange</code></li>
<li>The component is too specific to be reused across the application</li>
</ul>
<p><strong>Use OneSlotFactory when...</strong></p>
<ul>
<li>You want every text input, checkbox, or other field type to use a consistent custom design system component</li>
<li>You are integrating a UI library (Mantine, Chakra UI, Ant Design) and want all form fields to use its components</li>
<li>You need to apply a site-wide theme or accessibility enhancement to all fields at once</li>
<li>Changes must be consistent and enforced across multiple forms or pages</li>
</ul>
<a id="ready-made-mantine-theme-with-react-declarative-mantine" class="tsd-anchor"></a><h2 class="tsd-anchor-link">Ready-made Mantine theme with <code>react-declarative-mantine</code><a href="#ready-made-mantine-theme-with-react-declarative-mantine" 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>If you are using the <a href="https://mantine.dev/">Mantine</a> component library, <code>react-declarative-mantine</code> provides a complete <code>OneSlotFactory</code> with all field types redesigned to match Mantine's aesthetic — without requiring any changes to your JSON schemas.</p>
<pre><code class="bash"><span class="hl-5">npm</span><span class="hl-1"> </span><span class="hl-3">install</span><span class="hl-1"> </span><span class="hl-3">react-declarative-mantine</span>
</code><button type="button">Copy</button></pre>
<pre><code class="tsx"><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-2">MantineSlotFactory</span><span class="hl-1"> } </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">&#39;react-declarative-mantine&#39;</span><span class="hl-1">;</span><br/><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-2">One</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-5">App</span><span class="hl-1"> = () </span><span class="hl-4">=&gt;</span><span class="hl-1"> (</span><br/><span class="hl-1"> </span><span class="hl-6">&lt;</span><span class="hl-7">MantineSlotFactory</span><span class="hl-6">&gt;</span><br/><span class="hl-1"> </span><span class="hl-6">&lt;</span><span class="hl-7">One</span><span class="hl-1"> </span><span class="hl-8">fields</span><span class="hl-1">=</span><span class="hl-4">{</span><span class="hl-2">fields</span><span class="hl-4">}</span><span class="hl-1"> </span><span class="hl-8">handler</span><span class="hl-1">=</span><span class="hl-4">{</span><span class="hl-2">handler</span><span class="hl-4">}</span><span class="hl-1"> </span><span class="hl-6">/&gt;</span><br/><span class="hl-1"> </span><span class="hl-6">&lt;/</span><span class="hl-7">MantineSlotFactory</span><span class="hl-6">&gt;</span><br/><span class="hl-1">);</span>
</code><button type="button">Copy</button></pre>
<p>Your existing field schemas remain unchanged. The library swaps in Mantine-styled renderers for every field type automatically.</p>
<blockquote>
<p><strong>Tip:</strong> You can preview how the Mantine theme looks without installing anything at the
<a href="https://react-declarative-mantine.github.io/">Mantine theme playground</a>.</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="#custom-fields-component-injection-and-slotfactory"><span>Custom fields: <wbr/>Component injection and <wbr/>Slot<wbr/>Factory</span></a><ul><li><a href="#injecting-jsx-with-fieldtypecomponent"><span>Injecting JSX with <wbr/>Field<wbr/>Type.<wbr/>Component</span></a></li><li><ul><li><a href="#props-available-inside-element"><span>Props available inside element</span></a></li><li><a href="#writing-back-to-the-form"><span>Writing back to the form</span></a></li></ul></li><li><a href="#replacing-built-in-renderers-with-oneslotfactory"><span>Replacing built-<wbr/>in renderers with <wbr/>One<wbr/>Slot<wbr/>Factory</span></a></li><li><ul><li><a href="#available-slot-names"><span>Available slot names</span></a></li><li><a href="#slot-component-props"><span>Slot component props</span></a></li></ul></li><li><a href="#when-to-use-component-vs-oneslotfactory"><span>When to use <wbr/>Component vs <wbr/>One<wbr/>Slot<wbr/>Factory</span></a></li><li><a href="#ready-made-mantine-theme-with-react-declarative-mantine"><span>Ready-<wbr/>made <wbr/>Mantine theme with react-<wbr/>declarative-<wbr/>mantine</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>