Showcase

This section provides a series of working examples to demonstrate the capabilities of SmarkForm.

The goal of this section is to showcase what SmarkForm can do rather than explaining the underlying code even you can take a look at the HTML, CSS, and JavaScript tabs to glimpse the simplicity of the implementation.

👉 Each example is designed to highlight different features and functionalities.

👉 All examples are mostly unstyled to emphasize the fact that SmarkForm is layout-agnostic.

👉 If there is any further CSS, it is only in order to make more evident some features and you could check the applied styles in the CSS tab of each example.

👉 HTML/CSS code used in the examples is meant to be short and readable to make it easier to understand the concepts rather than to be best fit from the point of view of UX or semantics.

🚀 For detailed explanations and code walkthroughs, please refer to the other sections of this manual.

📖 Table of Contents

Basic Form

In this first example, we’ll start with a simple form that includes a few input fields (right side) and a textarea .

🗒️ HTML
⚙️ JS
👁️ Preview
📝 Notes
<div id="myForm">
    <div style="display: flex; align-items:center; gap: 1em; min-width: max(100%, 450px)">
        <div data-smark='{"name":"demo"}' style="flex-grow: 1">
        <h2>Car Details</h2>
        <p>
            <label data-smark>Model:</label>
            <input type="text" name="model" data-smark />
        </p>
        <p>
            <label data-smark>Doors:</label>
            <input type="number" name="doors" min="3" max="5" step=2 data-smark />
        </p>
        <p>
            <label data-smark>Seats:</label>
            <input type="number" name="seats" min=4 max=9 data-smark />
        </p>
        <p>
            <label data-smark>Driving Side:</label>
            <input type="radio" name="side" value="left" data-smark /> Left
            <input type="radio" name="side" value="right" data-smark /> Right
        </p>
        <p>
            <label data-smark>Color:</label>
            <span data-smark='{"type":"color", "name":"color"}'>
                <input data-smark>
                <button data-smark='{"action":"clear"}' title='Indifferent or unknown' ></button>
            </span>
        </p>
    </div>
        <div>
            <p><button
                data-smark='{"action":"export","context":"demo","target":"../editor"}'
                title="Export 'demo' subform to 'editor' textarea"
                >➡️ </button></p>
            <p><button
                data-smark='{"action":"import","context":"demo","target":"../editor"}'
                title="Import 'editor' textarea contents to 'demo' subform"
                >⬅️ </button></p>
            <span><button
                data-smark='{"action":"clear", "context":"demo"}'
                title="Clear the whole form"
                ></button></span>
        </div>
        <textarea
            cols="20"
            placeholder="JSON data viewer / editor"
            data-smark='{"name":"editor","type":"input"}'
            style="resize: none; align-self: stretch; min-height: 8em; flex-grow: 1;"
        ></textarea>

    </div>
</div>
const myForm = new SmarkForm(document.getElementById("myForm"));

Car Details

Left Right

👉 In this example you can:

  • Use the ➡️ buttorn to export the form as JSON into the textarea at the right.
  • Clear the form using the button.
  • Use the ⬅️ buttorn to import that JSON back to the form again.
  • Edit the JSON in the textarea as you like and click ⬅️ again to translate the changes to the form.
  • Try to import an invalid values for given field to see how the form handles it.
  • Notice that most SmarkForm fields can be null, meaning the data is unknown or indifferent.
  • Even color pickers can be null even native HTML color inputs can’t.
  • To reset a color picker after a color being set, we a button to call it’s “clear” action.
  • This kind of SmarkForm components intended to call actions on SmarkForm fields are called triggers.
  • There are several other actions that can be called on SmarkForm fields. Some, such as import and export are common to all field types and others are specific to some of them. For instance addItem and removeItem are specific to lists.

Don’t miss the 📝 Notes tab. There you’ll find useful guidelines and tips to deepen your understanding.

Nested forms

The former example example is entirely built with SmarkForm itself.

If you look at its JS tab you’ll see that there is no JavaScript code except for the SmarkForm instantiation itself.

👉 The trick here is that you did not import/export the whole form but just a subform.

  • The whole SmarkForm form is a field of the type “form” that imports/exports JSON and they can be nested up to any depth.

  • The ➡️ , ⬅️ and buttons are trigger components that perform specialized actions (look at the HTML tab to see how…).

  • Below these lines you can see the exact same form with additional 💾 and 📂 buttons and a little additional JavaScript code to mock the “save” and “load” operations through window’s alert() and prompt(), reespectively.

🗒️ HTML
⚙️ JS
👁️ Preview
📝 Notes
<div id="myForm">
    <div style="display: flex; align-items:center; gap: 1em; min-width: max(100%, 450px)">
        <div data-smark='{"name":"demo"}' style="flex-grow: 1">
        <h2>Car Details</h2>
        <p>
            <label data-smark>Model:</label>
            <input type="text" name="model" data-smark />
        </p>
        <p>
            <label data-smark>Doors:</label>
            <input type="number" name="doors" min="3" max="5" step=2 data-smark />
        </p>
        <p>
            <label data-smark>Seats:</label>
            <input type="number" name="seats" min=4 max=9 data-smark />
        </p>
        <p>
            <label data-smark>Driving Side:</label>
            <input type="radio" name="side" value="left" data-smark /> Left
            <input type="radio" name="side" value="right" data-smark /> Right
        </p>
        <p>
            <label data-smark>Color:</label>
            <span data-smark='{"type":"color", "name":"color"}'>
                <input data-smark>
                <button data-smark='{"action":"clear"}' title='Indifferent or unknown' ></button>
            </span>
        </p>
    </div>
        <div>
            <p><button
                data-smark='{"action":"export","context":"demo","target":"../editor"}'
                title="Export 'demo' subform to 'editor' textarea"
                >➡️ </button></p>
            <p><button
                data-smark='{"action":"import","context":"demo","target":"../editor"}'
                title="Import 'editor' textarea contents to 'demo' subform"
                >⬅️ </button></p>
            <p><button
                data-smark='{"action":"export"}'
                title="Export the whole form as JSON (see JS tab)"
                >💾</button></p>
            <p><button
                data-smark='{"action":"import"}'
                title="Import the whole form as JSON (see JS tab)"
                >📂</button></p>
            <span><button
                data-smark='{"action":"clear", "context":"demo"}'
                title="Clear the whole form"
                ></button></span>
        </div>
        <textarea
            cols="20"
            placeholder="JSON data viewer / editor"
            data-smark='{"name":"editor","type":"input"}'
            style="resize: none; align-self: stretch; min-height: 8em; flex-grow: 1;"
        ></textarea>

    </div>
</div>
const myForm = new SmarkForm(document.getElementById("myForm"));
myForm.on("BeforeAction_import", async (ev)=>{
    if (ev.context.getPath() !== "/") return; /* Only for root */
    /* Read previous value: */
    let previous_value = await ev.context.export();
    let isObject = typeof previous_value == "object";
    if (isObject) previous_value = JSON.stringify(previous_value);
    let data = window.prompt("Edit JSON data", previous_value);
    if (data === null) return void ev.preventDefault();
    try {
        if (isObject) data = JSON.parse(data);
        ev.data = data;
    } catch(err) {
        alert(err.message);
        ev.preventDefault();
    };
});
myForm.on("AfterAction_export", ({context, data})=>{
    if (context.getPath() !== "/") return; /* Only for root */
    if (typeof data == "object") data = JSON.stringify(data, null, 4);
    window.alert(data);
});

Car Details

Left Right

👉 Here you can:

  • Repeat all the same trials as in the former example (with identical results).
  • Use the 💾 button to export the whole form to a window.alert(...) dialog.
  • Use the 📂 button to import new JSON data to the whole form.
    • You can use the previously exported JSON as a base for custom edits.

👉 Despite of usability concerns, there is no limit in form nesting depth. For instance, the follwoing example shows a form with another level of nesting:

🗒️ HTML
⚙️ JS
👁️ Preview
📝 Notes
<div id="myForm">
    <div style="display: flex; align-items:center; gap: 1em; min-width: max(100%, 450px)">
        <div data-smark='{"name":"demo"}' style="flex-grow: 1">
        <h2>Car Details</h2>
        <p>
            <label data-smark>Model:</label>
            <input type="text" name="model" data-smark />
        </p>
        <p>
            <label data-smark>Doors:</label>
            <input type="number" name="doors" min="3" max="5" step=2 data-smark />
        </p>
        <p>
            <label data-smark>Seats:</label>
            <input type="number" name="seats" min=4 max=9 data-smark />
        </p>
        <p>
            <label data-smark>Driving Side:</label>
            <input type="radio" name="side" value="left" data-smark /> Left
            <input type="radio" name="side" value="right" data-smark /> Right
        </p>
        <p data-smark='{"name":"safety","type":"form"}'>
            <label>Safety Features:</label>
            <span>
                <label><input type="checkbox" name="airbag" data-smark /> Airbag.</label>
            </span>
            &nbsp;&nbsp;
            <span>
                <label><input type="checkbox" name="abs" data-smark /> ABS.</label>
            </span>
            &nbsp;&nbsp;
            <span>
                <label><input type="checkbox" name="esp" data-smark /> ESP.</label>
            </span>
            &nbsp;&nbsp;
            <span>
                <label><input type="checkbox" name="tc" data-smark />TC.</label>
            </span>
        </p>
        <p>
            <label data-smark>Color:</label>
            <span data-smark='{"type":"color", "name":"color"}'>
                <input data-smark>
                <button data-smark='{"action":"clear"}' title='Indifferent or unknown' ></button>
            </span>
        </p>
    </div>
        <div>
            <p><button
                data-smark='{"action":"export","context":"demo","target":"../editor"}'
                title="Export 'demo' subform to 'editor' textarea"
                >➡️ </button></p>
            <p><button
                data-smark='{"action":"import","context":"demo","target":"../editor"}'
                title="Import 'editor' textarea contents to 'demo' subform"
                >⬅️ </button></p>
            <p><button
                data-smark='{"action":"export"}'
                title="Export the whole form as JSON (see JS tab)"
                >💾</button></p>
            <p><button
                data-smark='{"action":"import"}'
                title="Import the whole form as JSON (see JS tab)"
                >📂</button></p>
            <span><button
                data-smark='{"action":"clear", "context":"demo"}'
                title="Clear the whole form"
                ></button></span>
        </div>
        <textarea
            cols="20"
            placeholder="JSON data viewer / editor"
            data-smark='{"name":"editor","type":"input"}'
            style="resize: none; align-self: stretch; min-height: 8em; flex-grow: 1;"
        ></textarea>

    </div>
</div>
const myForm = new SmarkForm(document.getElementById("myForm"));
myForm.on("BeforeAction_import", async (ev)=>{
    if (ev.context.getPath() !== "/") return; /* Only for root */
    /* Read previous value: */
    let previous_value = await ev.context.export();
    let isObject = typeof previous_value == "object";
    if (isObject) previous_value = JSON.stringify(previous_value);
    let data = window.prompt("Edit JSON data", previous_value);
    if (data === null) return void ev.preventDefault();
    try {
        if (isObject) data = JSON.parse(data);
        ev.data = data;
    } catch(err) {
        alert(err.message);
        ev.preventDefault();
    };
});
myForm.on("AfterAction_export", ({context, data})=>{
    if (context.getPath() !== "/") return; /* Only for root */
    if (typeof data == "object") data = JSON.stringify(data, null, 4);
    window.alert(data);
});

Car Details

Left Right

        

👉 Again, despite importing and exporting the demo subform with ➡️ and ⬅️ buttons you can, respectively:

  • Use the 💾 button to see the whole form in a window.alert(...) dialog.
  • And 📂 button to import a new JSON data to the whole form throught a window.prompt(...).

🚀 See the Nested lists and forms section down below for more elaborated examples of nested forms.

A note on context of the triggers

In the previous example, the 💾 and 📂 buttons operate on the whole form because it is their natural context.

In the case of the ➡️ , ⬅️ and buttons, they have their context explicitly set by the option of the same name.

We could have wanted to make the 💾 and 📂 buttons to operate only on the demo subform.

We could have done that by setting their context property to “demo”.

From now on, except for the following example, having we already demonstrated how to work with import and export actions’ eveents, for the sake of simplicity we’ll stick to the layout of the very first example (➡️ , ⬅️ and buttons targetting the “editor” textarea) that doesn’t need any additionally JS code.

…But, also, we could just have placed them inside of that context in the markup as is showing in the following example:

🗒️ HTML
⚙️ JS
👁️ Preview
📝 Notes
<div id="myForm">
    <div style="display: flex; align-items:center; gap: 1em; min-width: max(100%, 450px)">
        <div data-smark='{"name":"demo"}' style="flex-grow: 1">
        <h2>Car Details</h2>
        <p>
            <label data-smark>Model:</label>
            <input type="text" name="model" data-smark />
        </p>
        <p>
            <label data-smark>Doors:</label>
            <input type="number" name="doors" min="3" max="5" step=2 data-smark />
        </p>
        <p>
            <label data-smark>Seats:</label>
            <input type="number" name="seats" min=4 max=9 data-smark />
        </p>
        <p>
            <label data-smark>Driving Side:</label>
            <input type="radio" name="side" value="left" data-smark /> Left
            <input type="radio" name="side" value="right" data-smark /> Right
        </p>
        <p data-smark='{"name":"safety","type":"form"}'>
            <label>Safety Features:</label>
            <span>
                <label><input type="checkbox" name="airbag" data-smark /> Airbag.</label>
            </span>
            &nbsp;&nbsp;
            <span>
                <label><input type="checkbox" name="abs" data-smark /> ABS.</label>
            </span>
            &nbsp;&nbsp;
            <span>
                <label><input type="checkbox" name="esp" data-smark /> ESP.</label>
            </span>
            &nbsp;&nbsp;
            <span>
                <label><input type="checkbox" name="tc" data-smark />TC.</label>
            </span>
        </p>
        <p>
            <label data-smark>Color:</label>
            <span data-smark='{"type":"color", "name":"color"}'>
                <input data-smark>
                <button data-smark='{"action":"clear"}' title='Indifferent or unknown' ></button>
            </span>
        </p>
        <p>
            <button
                data-smark='{"action":"export"}'
                title="Export the whole form as JSON (see JS tab)"
                >💾 Save</button>
            <button
                data-smark='{"action":"import"}'
                title="Import the whole form as JSON (see JS tab)"
                >📂 Load</button>
        </p>
        </div>
        <div>
            <p><button
                data-smark='{"action":"export","context":"demo","target":"../editor"}'
                title="Export 'demo' subform to 'editor' textarea"
                >➡️ </button></p>
            <p><button
                data-smark='{"action":"import","context":"demo","target":"../editor"}'
                title="Import 'editor' textarea contents to 'demo' subform"
                >⬅️ </button></p>
            <span><button
                data-smark='{"action":"clear", "context":"demo"}'
                title="Clear the whole form"
                ></button></span>
        </div>
        <textarea
            cols="20"
            placeholder="JSON data viewer / editor"
            data-smark='{"name":"editor","type":"input"}'
            style="resize: none; align-self: stretch; min-height: 8em; flex-grow: 1;"
        ></textarea>

    </div>
</div>
const myForm = new SmarkForm(document.getElementById("myForm"));
myForm.on("BeforeAction_import", async (ev)=>{
    if (!! ev.target) return; /* Only for triggers without target */
    /* Read previous value: */
    let previous_value = await ev.context.export();
    let isObject = typeof previous_value == "object";
    if (isObject) previous_value = JSON.stringify(previous_value);
    let data = window.prompt("Edit JSON data", previous_value);
    if (data === null) return void ev.preventDefault();
    try {
        if (isObject) data = JSON.parse(data);
        ev.data = data;
    } catch(err) {
        alert(err.message);
        ev.preventDefault();
    };
});
myForm.on("AfterAction_export", ({target, data})=>{
    if (!! target) return; /* Only for triggers without target */
    if (typeof data == "object") window.alert(JSON.stringify(data, null, 4));
});

Car Details

Left Right

        

If you compare the JS tab with the one in fhe former one, you’ll see that there is a little difference between them.

👉 In the first one, the “BeforeAction_import” and “AfterAction_export” event handlers inhibits themselves depending on whether the context is the root form or not while, in the later, it just focus on the fact that the target is not provided.

👉 The second is a more generic approach for this kind of event handlers. But the first one serves as an alternative example showing how we can base those event handlers’ behaviour on the specific context (path) of every trigger.

👉 Now the 💾 Save and 📂 Load buttons work on the “/demo” path (that is: they only import/export the “demo” subform) just like ➡️ and ⬅️ ones do but without explicitly specifying their context.

👌 If you want a clearer example on how the context affect the triggers, take a look to the following example:

🗒️ HTML
⚙️ JS
👁️ Preview
📝 Notes
<div id='myForm'>
    <p>
        <label data-smark>Name:</label>
        <input name='name' data-smark>
    </p>
    <p>
        <label data-smark>Surname:</label>
        <input name='surname' data-smark>
    </p>
    <table>
        <tr>
            <th>Whole Form:</th>
            <td><button data-smark='{"action":"import"}'>⬆️  Import</button></td>
            <td><button data-smark='{"action":"export"}'>⬇️  Export</button></td>
        </tr>
        <tr>
            <th>Name field:</th>
            <td><button data-smark='{"action":"import","context":"name"}'>⬆️  Import</button></td>
            <td><button data-smark='{"action":"export","context":"name"}'>⬇️  Export</button></td>
        </tr>
        <tr>
            <th>Surname field:</th>
            <td><button data-smark='{"action":"import","context":"surname"}'>⬆️  Import</button></td>
            <td><button data-smark='{"action":"export","context":"surname"}'>⬇️  Export</button></td>
        </tr>
    </table>
</div>
const myForm = new SmarkForm(document.getElementById("myForm"));
myForm.on("BeforeAction_import", async (ev)=>{
    /* Read previous value: */
    let previous_value = await ev.context.export();
    let isObject = typeof previous_value == "object";
    if (isObject) previous_value = JSON.stringify(previous_value);
    let data = window.prompt(`Edit ${ev.context.getPath()}`, previous_value);
    if (data === null) return void ev.preventDefault();
    try {
        if (isObject) data = JSON.parse(data);
        ev.data = data;
    } catch(err) {
        alert(err.message);
        ev.preventDefault();
    };
});
myForm.on("AfterAction_export", ({context, data})=>{
    if (typeof data == "object") data = JSON.stringify(data, null, 4);
    window.alert(`Value of ${context.getPath()}: ${data}`);
});

Whole Form:
Name field:
Surname field:

👉 Notice that all Import and Export buttons (triggers) are handled by the same event handlers (for “BeforeAction_import” and “AfterAction_export”, respectively).

👉 They belong to different SmarkForm fields determined by (1) where they are placed in the DOM and (2) the relative path from that place pointed by the context property.

ℹ️ Different field types may import/export different data types (forms import/export JSON while regular inputs import/export text).

🔧 For the sake of simplicity, the BeforeAction_import event handler reads the previous value of the field (no matter its type) and provides it stringified as JSON as default value for the window.prompt() call. Making it easy to edit the value no matter if we are importing one of the text fields or the whole form.

Lists

One of the most powerful features of SmarkForm is its ability to handle variable-length lists.

Let’s say you need to collect phone numbers or emails from users. Instead of having (and dealing with it) a fixed number of input fields, you can use a list that can grow or shrink as needed:

🗒️ HTML
⚙️ JS
👁️ Preview
<div id="myForm">
    <div style="display: flex; align-items:center; gap: 1em; min-width: max(100%, 450px)">
        <div data-smark='{"name":"demo"}' style="flex-grow: 1">
            <button data-smark='{"action":"removeItem", "context":"phones"}' title='Remove phone number'></button>
            <button data-smark='{"action":"addItem","context":"phones"}' title='Add phone number'></button>
            <label data-smark>Phones:</label>
            <div data-smark='{"type":"list", "name": "phones", "of": "input", "exportEmpties": true}'>
                <input type="tel" style="display: block">
            </div>

        </div>
        <div>
            <p><button
                data-smark='{"action":"export","context":"demo","target":"../editor"}'
                title="Export 'demo' subform to 'editor' textarea"
                >➡️ </button></p>
            <p><button
                data-smark='{"action":"import","context":"demo","target":"../editor"}'
                title="Import 'editor' textarea contents to 'demo' subform"
                >⬅️ </button></p>
            <span><button
                data-smark='{"action":"clear", "context":"demo"}'
                title="Clear the whole form"
                ></button></span>
        </div>
        <textarea
            cols="20"
            placeholder="JSON data viewer / editor"
            data-smark='{"name":"editor","type":"input"}'
            style="resize: none; align-self: stretch; min-height: 8em; flex-grow: 1;"
        ></textarea>

    </div>
</div>
const myForm = new SmarkForm(document.getElementById("myForm"));

Here we used a simpple <input> field for each item in the list and had to trick them with style="display: block;" to make them to stack gracefully.

But lists are even more powerful than that:

For instance, we could have used a form field instead, but in this case we would had get a JSON object for each item in the list, which is not what we want in this specific case.

👉 To address this issue, we can take advantage of the singleton pattern to make any HTML element to become a regular input field.

We call the singleton pattern when we use any HTML element different from <input>, <select>, <textarea>, etc., as a regular input field.

For this to work we only need to place one (and only one) of these elements with the “data-smark” attribute in its contents. …

This way we can not only use a more elaborated structure for each item in the list: It also allows us to include other controls within every list item, like in the following example:

🗒️ HTML
⚙️ JS
👁️ Preview
<div id="myForm">
    <div style="display: flex; align-items:center; gap: 1em; min-width: max(100%, 450px)">
        <div data-smark='{"name":"demo"}' style="flex-grow: 1">
            <button data-smark='{"action":"removeItem", "context":"phones", "target":"*", "keep_non_empty":true}' title='Remove unused fields'>🧹</button>
            <button data-smark='{"action":"removeItem", "context":"phones", "keep_non_empty":true}' title='Remove phone number'></button>
            <button data-smark='{"action":"addItem","context":"phones"}' title='Add phone number'></button>
            <label data-smark>Phones:</label>
            <ul data-smark='{"name": "phones", "of": "input", "sortable":true, "min_items":0, "max_items":5}'>
                <li data-smark='{"role": "empty_list"}' class="row">(None)</li>
                <li class="row">
                    <label data-smark>📞 </label><input type="tel" data-smark>
                    <button data-smark='{"action":"removeItem"}' title='Remove this phone number'></button>
                </li>
            </ul>

        </div>
        <div>
            <p><button
                data-smark='{"action":"export","context":"demo","target":"../editor"}'
                title="Export 'demo' subform to 'editor' textarea"
                >➡️ </button></p>
            <p><button
                data-smark='{"action":"import","context":"demo","target":"../editor"}'
                title="Import 'editor' textarea contents to 'demo' subform"
                >⬅️ </button></p>
            <p><button
                data-smark='{"action":"clear", "context":"demo"}'
                title="Clear the whole form"
                ></button></p>
        </div>
        <textarea
            cols="20"
            placeholder="JSON data viewer / editor"
            data-smark='{"name":"editor","type":"input"}'
            style="resize: none; align-self: stretch; min-height: 8em; flex-grow: 1;"
        ></textarea>

    </div>
</div>
const myForm = new SmarkForm(document.getElementById("myForm"));
  • (None)

👉 In this example we:

  • Established a maximum of 5 items in the list.

  • Allowed the list to be empty (default minimum items is 1).

  • Defined an alternate template for the case of empty list.

  • Made the button a little smarter so that it removes empty items, if any, first.

  • Added a 🧹 button to remove all empty items.

  • Added a button to each item to cherry-pick which items to remove.

  • Returned to the default behaviour of not exporting empty items.

  • Made it sortable (by dragging and dropping items).

👉 And there is a lot more… To begin with, another interesting use case for lists is to create a schedule list like the following example:

🗒️ HTML
⚙️ JS
👁️ Preview
<div id="myForm">
    <div style="display: flex; flex-direction:column; align-items:left; gap: 1em; min-width: max(100%, 450px)">
        <div data-smark='{"name":"demo"}' style="flex-grow: 1">
            <p>
                <button data-smark='{"action":"removeItem","hotkey":"-","context":"schedule"}' title='Less intervals'></button>
                <button data-smark='{"action":"addItem","hotkey":"+","context":"schedule"}' title='More intrevals'></button>
                <label>Schedule:</label>
                <span data-smark='{"type":"list","name":"schedule","min_items":0,"max_items":3}'>
                    <span>
                        <input class='small' data-smark type='time' name='start'> to <input class='small' data-smark type='time' name='end'>
                    </span>
                    <span data-smark='{"role":"empty_list"}'>(Closed)</span>
                    <span data-smark='{"role":"separator"}'>, </span>
                    <span data-smark='{"role":"last_separator"}'> and </span>
                </span>
            </p>

        </div>
        <div>
            <span><button
                data-smark='{"action":"export","context":"demo","target":"../editor"}'
                title="Export 'demo' subform to 'editor' textarea"
                >⬇️ </button></span>
            <span><button
                data-smark='{"action":"import","context":"demo","target":"../editor"}'
                title="Import 'editor' textarea contents to 'demo' subform"
                >⬆️ </button></span>
            <span><button
                data-smark='{"action":"clear", "context":"demo"}'
                title="Clear the whole form"
                ></button></span>
        </div>
        <textarea
            cols="20"
            placeholder="JSON data viewer / editor"
            data-smark='{"name":"editor","type":"input"}'
            style="resize: none; align-self: stretch; min-height: 8em; flex-grow: 1;"
        ></textarea>

    </div>
</div>
const myForm = new SmarkForm(document.getElementById("myForm"));

to (Closed) , and

👉 Or we could have wanted a more formal (or better aligned, in case of multiple schedules) layout such as a table:

🚧 Missing Example

Example id misspelled or not yet implemented: schedule_table.

Nested lists and forms

Section still under construction…

Since we can make lists of forms, we can also nest more forms and lists inside every list item and so forth to any depth.

🚧 Missing Example

Example id misspelled or not yet implemented: nested_lists.

There is no theoretical limit to the depth of nesting beyond the logical usability concerns.

Here is a more complex example with a deeply nested form:

🚧 Missing Example

Example id misspelled or not yet implemented: deeply_nested_form.

These are just simple examples to show the concept. You can see more elaborated examples in the Examples section of this documentation.

Context-Driven Keyboard Shortcuts

Section still under construction…

SmarkForm supports context-driven keyboard shortcuts, enhancing the user experience by allowing quick navigation and actions. This example will demonstrate how to configure and use these shortcuts in your forms.

🚧 Missing Example

Example id misspelled or not yet implemented: keyboard_shortcuts.

Dynamic Dropdown Options

Section still under construction…

In this example, we’ll illustrate how to create dropdown menus with dynamic options. This is particularly useful for forms that need to load options based on user input or external data sources.

🚧 Missing Example

Example id misspelled or not yet implemented: dynamic_dropdown.

Import and Export Data

Section still under construction…

SmarkForm makes it easy to import and export form data in JSON format. This example will show how to load data into a form and export it, ensuring proper data handling and integration with other systems.

🚧 Missing Example

Example id misspelled or not yet implemented: import_export.

Smart value coercion

Section still under construction…

🚧 Missing Example

Example id misspelled or not yet implemented: smart_value_coercion.

Advanced UX Improvements

Section still under construction…

Finally, we’ll showcase some advanced user experience improvements that SmarkForm offers, such as smart auto-enablement/disablement of controls and non-breaking unobtrusive keyboard navigation.

🚧 Missing Example

Example id misspelled or not yet implemented: advanced_ux.

Conclusion

Section still under construction…

We hope these examples have given you a good overview of what SmarkForm can do. By leveraging the power of markup-driven forms, SmarkForm simplifies the creation of interactive and intuitive forms, allowing you to focus on your application’s business logic. Feel free to experiment with these examples and adapt them to suit your specific needs.

For more detailed information and documentation, please refer to the other sections of this manual. If you have any questions or need further assistance, don’t hesitate to reach out to the SmarkForm community.

Happy form building!