SmarkForm

🚀 Powerful while effortless Markup-driven and Extendable form controller.

NPM Version npm dependencies NPM Downloads jsDelivr Hits License

SmarkForm is a lightweight and extendable form controller that enhances HTML forms to support subforms and variable-length lists without tying the layout to any specific structure. This enable it to import and export data in JSON format, while providing a smooth navigation with configurable hotkeys and a low-code experience among other features. [More…]

Main Features

  • <> Markup agnostic: Maximum decoupling between design and development teams.
  • 🧩 Low code: No manual wiring between controls and fields.
  • 🗂 Subforms: Nested forms to any depth.
  • 📑 Lists: Sortable and variable-length lists (arrays) either of scalars or subforms.
  • 🫳 Configurable hot keys: Context-driven and discoverable keyboard shortcuts.
  • 🫶 Consistent UX: Smooth navigation and consistent behaviour across all forms.
  • {} JSON format: Data is imported / exported as JSON.
  • 🪶 Lightweight: Only 37KB minified.
  • 💪 Flexible, extendable and more…

Sample Code

The following code snippet shows SmarkForm simplicity.

👉 You will find similar examples working preview along this documentation. Don’t miss the 📝 Notes tab to be aware of the nitty-gritty details.

🔗
🗒️ HTML
🎨 CSS
⚙️ JS
👁️ Preview
📝 Notes
<div id="myForm">
    <p>
        <label data-smark='{"type": "label"}'>Name:</label>
        <input name='name' data-smark='{"type": "input"}' />
    </p>
    <p>
        <label data-smark='{"type": "label"}'>Surname:</label>
        <input name='surname' data-smark='{"type": "input"}' />
    </p>
    <button data-smark='{"action":"removeItem", "context":"phones", "target":"*", "hotkey":"Delete", "keep_non_empty":true}' title='Remove unused fields'>🧹</button>
    <button data-smark='{"action":"removeItem", "context":"phones", "hotkey":"-", "keep_non_empty":true}' title='Remove phone number'></button>
    <button data-smark='{"action":"addItem","context":"phones", "hotkey":"+"}' title='Add phone number'></button>
    <label data-smark>Phones:</label>
    <ul data-smark='{"name": "phones", "of": "input", "sortable":true, "max_items":5, "exportEmpties": true}'>
        <li class="row">
            <label data-smark>📞 Telephone
            <span data-smark='{"action":"position"}'>N</span>
            </label>
            <button data-smark='{"action":"removeItem", "hotkey":"-"}' title='Remove this phone number'></button>
            <input type="tel" data-smark>
            <button data-smark='{"action":"addItem", "hotkey":"+"}' title='Insert phone number'></button>
        </li>
    </ul>
</div>
/* Materialize hotkey hints from data-hotkey attribute */
#myForm [data-hotkey] {
  position: relative;
  overflow-x: display;
}
#myForm [data-hotkey]::before {
  content: attr(data-hotkey);
  display: inline-block;
  position: absolute;
  top: 2px;
  left: 2px;
  z-index: 10;
  pointer-events: none;
  background-color: #ffd;
  outline: 1px solid lightyellow;
  padding: 2px 8px;
  border-radius: 4px;
  font-weight: bold;
  font-family: sans-serif;
  font-size: 0.8em;
  white-space: nowrap;
  transform: scale(1.8) translate(0.1em, 0.1em);
}
/* Hide list bullets */
#myForm ul li {
    list-style-type: none;
}
/* Make disabled buttons more evident: */
#myForm :disabled {
    opacity: 0.4;
}

const myForm = new SmarkForm(document.getElementById("myForm"));

👉 This is a simple form to show the power of SmarkForm.

  • Tinker with it in the Preview tab, modifying data, etc…
    • Add or remove items from the Phones list.
    • Sort the list by dragging them with the mouse.
    • Use the ⬇️ to export the data as JSON.
    • Use the to clear the form.
    • Use the ⬆️ to import the JSON back to the form. You can modify the JSON before importing it back.
  • Notice you can navigate forward and backward using the keyboard:
    • Using the Enter and Shift+Enter from field to field bypassing control buttons.
    • Using the Tab and Shift+Tab as usual, to reach both fields and control buttons.
    • Don’t miss the hotkeys! Move the focus to a telephone field and hit the Ctrl key to see the avaliable ones (depending on focused context) revealed.

👉 Its behavior is driven by the data-smark attributes, which are declarative and intuitive with straightforward defaults to match most common use cases.

  • …for instance, min_items is set to 1 by default, so you cannot remove the last item from the Phones list. But you can change it by setting min_items to 0, allowing an empty list.

  • Another interesting case is the exportEmpties property, which is set to false by default, so empty items are not usually exported. In this example, it is set to true since, for a first contact, it might seem counterintuitive.

👉 Check the JS tab to see the little JS just to initialize it as a SmarkForm and show you the data when exported.

👉 In the CSS tab you will find some non-essential CSS primarily to materialize hotkeys’ revealing feature when pressing the Ctrl key.

To minimize clutter, the ⬇️ Export, ⬆️ Import and ❌ Clear buttons implementation have been omitted from the source code, as they are common to all examples and will be explained in detail in a 🔗 later section.

Current Status

SmarkForm implementation is stable and fully functional, but not all initially planned requirements are yet implemented. Hence, it’s not yet in the 1.0.0 version. [🔗 More…]

Last Updated: Thu Aug 21 2025.

Where to Go Next?

To get started with SmarkForm you can:

👉 Take a look to our 🔗 Showcase section to see its full potential at a glance.
👉 Follow our 🔗 Quick Start Guide to rapidly dive in.
👉 Check out our 🔗 Downloadable Examples to see them in action and/or start tinkering.

License

🔗 MIT

Contributing

We welcome any feedback, suggestions, or improvements as we continue to enhance and expand the functionality of SmarkForm.


Hello footer