This guide explains how to create and use custom form field elements with tiny-form-fields.
tiny-form-fields supports custom form field elements through web components. This allows you to:
- Create custom input types with specific validation and behavior
- Extend the library with your own form field implementations
- Reuse your custom elements across different forms
First, include the base class in your HTML:
<script src="node_modules/tiny-form-fields/dist/base-custom-field.js" type="module"></script>Or import it in your JavaScript:
import { BaseCustomField } from './node_modules/tiny-form-fields/dist/base-custom-field.js';Create a new class that extends BaseCustomField:
class MyCustomInput extends BaseCustomField {
constructor() {
super();
}
// Optional: Implement custom validation
validate() {
// Your validation logic here
return true; // or false if validation fails
}
}
// Register your component
customElements.define('my-custom-input', MyCustomInput);The BaseCustomField class provides:
- Automatic attribute transfer from custom element to internal input
- Event handling and forwarding
- Mutation observation for attribute changes
Add your custom element to the shortTextTypeList when initializing tiny-form-fields:
const app = Elm.Main.init({
node: document.getElementById('myapp'),
flags: {
shortTextTypeList: [{
inputType: "My Custom Input", // Display name in the form builder
inputTag: "my-custom-input", // Your custom element tag name
attributes: { // HTML attributes to apply
"type": "text", // Base input type
"data-custom": "value" // Any custom attributes
}
}]
}
});Here's a complete example of creating a custom validated input field that checks for a specific length:
import { BaseCustomField } from './dist/base-custom-field.js';
class ValidatedInput extends BaseCustomField {
constructor() {
super();
}
validate() {
// First, clear any previous custom validity message
super.validate();
const value = this.input.value;
let validityMessage = '';
// Custom validation logic
if (value.length !== 9 && value !== '') {
validityMessage = 'Input must be exactly 9 characters long.';
}
// Set custom validity on the internal input
this.input.setCustomValidity(validityMessage);
}
}
customElements.define('validated-input', ValidatedInput);
// Configure in tiny-form-fields
const app = Elm.Main.init({
node: document.getElementById('tiny-form-fields'),
flags: {
viewMode: "Editor",
shortTextTypeList: [{
"Custom Element": {
"inputTag": "validated-input",
"attributes": {
"type": "url"
}
}
}]
}
});-
The
BaseCustomFieldclass handles:- Creation and management of the internal input element
- Event forwarding from the custom element to the internal input
- Attribute synchronization via MutationObserver
- Lifecycle management (connection/disconnection)
- Event listener management for input validation
-
Your custom element can utilize:
validate()method for custom validation logic usingsetCustomValidityconnectedCallback()for additional setup (handled by base class)disconnectedCallback()for cleanup (handled by base class)
-
The
shortTextTypeListconfiguration accepts:- A map where the key is the display name (e.g. "Custom Element")
- An object containing:
inputTag: The HTML tag name for your custom elementattributes: HTML attributes to apply to the input
-
Custom elements are automatically integrated into the form builder UI and will appear in the input type dropdown menu.
- Always extend
BaseCustomFieldto ensure consistent behavior - Use
setCustomValidityfor validation messages - Clear previous validity messages before setting new ones
- Keep validation logic simple and focused
- Use type="module" when importing the BaseCustomField
- Test your custom element thoroughly before integration
For a working example, refer to the index.html file in the tiny-form-fields repository.