Now.js Framework Documentation
Special Elements
Special Elements
Documentation for specialized form elements: ColorElementFactory, RangeElementFactory, TagsElementFactory, MaskElementFactory, and TextareaElementFactory.
📋 Table of Contents
- Overview
- ColorElementFactory
- RangeElementFactory
- TagsElementFactory
- MaskElementFactory
- TextareaElementFactory
- Best Practices
Overview
Special elements provide enhanced UI for specific input types that need more than basic text or number handling.
| Element | data-element | Description |
|---|---|---|
| ColorElementFactory | color |
Color picker with palette |
| RangeElementFactory | range |
Single/dual range slider |
| TagsElementFactory | tags |
Tags/chips input with autocomplete |
| MaskElementFactory | mask |
Input masking (phone, date, etc.) |
| TextareaElementFactory | textarea |
Auto-resize textarea |
ColorElementFactory
ColorElementFactory creates a custom color picker with predefined palette and hex input.
Basic Usage
<input type="color"
data-element="color"
name="theme_color"
value="#007bff">
<!-- Or with text input -->
<input type="text"
data-element="color"
name="bg_color"
value="#ffffff">HTML Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
data-element |
string | - | Set to color |
value |
string | #000000 |
Initial color (hex) |
disabled |
boolean | false |
Disable picker |
readonly |
boolean | false |
Read-only mode |
Default Color Palette
const COLOR_PALETTE = [
'#FF5722', '#F44336', '#E91E63', '#9C27B0',
'#673AB7', '#3F51B5', '#2196F3', '#03A9F4',
'#00BCD4', '#009688', '#4CAF50', '#8BC34A',
'#CDDC39', '#FFEB3B', '#FFC107', '#FF9800',
// ... and more standard colors
'#FFFFFF', '#000000'
];JavaScript API
const instance = ElementManager.getInstance(colorInput);
// Get current color
const color = instance.getColor(); // '#007bff'
// Set color
instance.setColor('#ff5722');
// Open/close picker
instance.open();
instance.close();
instance.toggle();
// Disable/enable
instance.setDisabled(true);
instance.setReadonly(true);Features
- Color Palette: Click predefined colors
- Hex Input: Type custom hex values
- Preview: Color preview in button
- Copy/Paste: Ctrl+C to copy, Ctrl+V to paste colors
- Contrast Text: Button text auto-adjusts for visibility
Events
colorInput.addEventListener('change', (e) => {
console.log('Selected color:', e.target.value);
});RangeElementFactory
RangeElementFactory creates enhanced range sliders with better UX than native range inputs. Supports single and dual range modes.
Basic Usage
<!-- Single range slider -->
<input type="range"
data-element="range"
min="0"
max="100"
value="50"
name="volume">
<!-- Dual range slider (min-max) -->
<input type="range"
data-element="range"
min="0"
max="1000"
data-value="200-800"
data-dual="true"
name="price_range">HTML Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
data-element |
string | - | Set to range |
min |
number | 0 |
Minimum value |
max |
number | 100 |
Maximum value |
step |
number | 1 |
Step increment |
value |
string | - | Single value or "min-max" for dual |
data-dual |
boolean | false |
Enable dual handles |
data-show-value |
boolean | true |
Show value label |
data-format |
string | - | Value format (e.g., {value}%) |
disabled |
boolean | false |
Disable slider |
readonly |
boolean | false |
Read-only mode |
Single Range
<input type="range"
data-element="range"
min="0"
max="100"
step="5"
value="75"
data-format="{value}%"
name="opacity">Dual Range (Min-Max)
<input type="range"
data-element="range"
min="0"
max="10000"
step="100"
data-value="2000-8000"
data-dual="true"
data-format="฿{value}"
name="budget">JavaScript API
const instance = ElementManager.getInstance(rangeInput);
// Get value
const value = instance.getValue();
// Single: 75
// Dual: {min: 2000, max: 8000}
// Set value
instance.setValue(80); // Single
instance.setValue({min: 1000, max: 5000}); // Dual
// Update constraints
instance.setMin(10);
instance.setMax(200);
instance.setStep(10);
// Enable/disable
instance.setDisabled(true);
instance.setReadonly(true);Keyboard Navigation
| Key | Action |
|---|---|
← / ↓ |
Decrease by step |
→ / ↑ |
Increase by step |
Home |
Go to min |
End |
Go to max |
Page Up |
Increase by 10 steps |
Page Down |
Decrease by 10 steps |
Events
// Input event (while dragging)
rangeInput.addEventListener('input', (e) => {
console.log('Current value:', e.detail.value);
});
// Change event (after release)
rangeInput.addEventListener('change', (e) => {
console.log('Final value:', e.detail.value);
});TagsElementFactory
TagsElementFactory transforms text input into a tags/chips input with visual tags, keyboard navigation, and optional autocomplete.
Basic Usage
<!-- Simple tags input -->
<input type="text"
data-element="tags"
name="keywords"
placeholder="Add tags...">
<!-- Tags with autocomplete -->
<input type="text"
data-element="tags"
data-source="/api/tags"
name="categories">
<!-- Tags with datalist -->
<input type="text"
data-element="tags"
list="available-tags"
name="skills">
<datalist id="available-tags">
<option value="1" label="JavaScript">
<option value="2" label="Python">
<option value="3" label="React">
</datalist>HTML Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
data-element |
string | - | Set to tags |
data-source |
string/array | - | Autocomplete source |
data-separator |
string | , |
Separator for pasted values |
data-max-tags |
number | null | Maximum tags allowed |
data-duplicate |
boolean | false |
Allow duplicate tags |
data-placeholder |
string | 'Add tags...' |
Input placeholder |
data-min-length |
number | 2 |
Min chars for autocomplete |
data-options-key |
string | - | Key for parent options data |
list |
string | - | Datalist ID for options |
Configuration
TagsElementFactory.config = {
type: 'text',
placeholder: 'Add tags...',
separator: ',',
maxTags: null,
allowDuplicate: false,
minLength: 2,
maxResults: 10,
delay: 300
};Keyboard Interaction
| Key | Action |
|---|---|
Enter |
Add current text as tag |
Backspace |
Remove last tag (when input empty) |
↓ / ↑ |
Navigate autocomplete |
Escape |
Close autocomplete |
JavaScript API
const instance = ElementManager.getInstance(tagsInput);
// Get all tags
const tags = instance.getTags();
// [{key: '1', value: 'JavaScript'}, {key: '2', value: 'Python'}]
// Add tag
instance.addTag('3', 'React');
// Remove tag
instance.removeTag('2');
// Set all tags
instance.setTags([
{key: '1', value: 'JavaScript'},
{key: '4', value: 'Vue'}
]);
// Clear all
instance.clear();
// Update autocomplete options
instance.updateOptions([
{value: '1', text: 'JavaScript'},
{value: '2', text: 'Python'}
]);Form Submission
Tags are submitted as hidden inputs:
<!-- Original input -->
<input data-element="tags" name="skills">
<!-- Generated hidden inputs -->
<input type="hidden" name="skills[]" value="1">
<input type="hidden" name="skills[]" value="2">
<input type="hidden" name="skills[]" value="3">Events
tagsInput.addEventListener('change', (e) => {
const instance = ElementManager.getInstance(e.target);
console.log('Tags:', instance.getTags());
});TagsElementFactory emits no tags:* events — adding or removing a tag fires the
native change event only. Compare instance.getTags() against the previous
list if you need to know which tag moved.
MaskElementFactory
MaskElementFactory applies input masks for structured data like phone numbers, dates, credit cards, etc.
Basic Usage
<!-- Phone number -->
<input type="tel"
data-element="mask"
data-mask="(###) ###-####"
name="phone">
<!-- Thai phone -->
<input type="tel"
data-element="tel"
name="mobile">
<!-- Credit card -->
<input type="text"
data-element="mask"
data-mask="#### #### #### ####"
name="card">
<!-- Date -->
<input type="text"
data-element="mask"
data-mask="##/##/####"
name="date">HTML Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
data-element |
string | - | mask or tel |
data-mask |
string | - | Mask pattern |
data-placeholder-char |
string | _ |
Character for unfilled positions |
data-mask-on-init |
boolean | true |
Apply mask on init |
data-mask-on-change |
boolean | true |
Apply mask on change |
data-mask-on-blur |
boolean | true |
Apply mask on blur |
data-unmask-on-submit |
boolean | false |
Remove mask on form submit |
Mask Pattern Characters
| Character | Accepts |
|---|---|
# |
Digit (0-9) |
A |
Letter (A-Z, a-z) |
* |
Alphanumeric |
| Other | Literal (shown as-is) |
Common Patterns
| Use Case | Pattern | Example |
|---|---|---|
| US Phone | (###) ###-#### |
(123) 456-7890 |
| Thai Phone | ###-###-#### |
081-234-5678 |
| Date | ##/##/#### |
31/12/2025 |
| Time | ##:## |
14:30 |
| Credit Card | #### #### #### #### |
1234 5678 9012 3456 |
| SSN | ###-##-#### |
123-45-6789 |
| Zip+4 | #####-#### |
12345-6789 |
TelElementFactory
Specialized mask for Thai phone numbers:
<input type="tel"
data-element="tel"
name="phone">
<!-- Auto applies: ###-###-#### -->JavaScript API
const instance = ElementManager.getInstance(maskedInput);
// Get unmasked value
const raw = instance.getUnmaskedValue(); // '0812345678'
// Get masked value
const masked = instance.getValue(); // '081-234-5678'
// Set value (auto-masked)
instance.setValue('0898765432');
// Shows: 089-876-5432Events
maskedInput.addEventListener('change', (e) => {
const instance = ElementManager.getInstance(e.target);
console.log('Masked:', e.target.value);
console.log('Raw:', instance.getUnmaskedValue());
});TextareaElementFactory
TextareaElementFactory enhances textarea with auto-resize functionality.
Basic Usage
<textarea data-element="textarea"
name="description"
rows="3"
placeholder="Enter description..."></textarea>HTML Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
data-element |
string | - | Set to textarea |
data-auto-resize |
boolean | true |
Enable auto-resize |
data-min-rows |
number | 3 |
Minimum rows |
data-max-rows |
number | 10 |
Maximum rows before scroll |
maxlength |
number | - | Character limit |
data-show-counter |
boolean | false |
Show character counter |
Auto-Resize Behavior
The textarea automatically adjusts height based on content:
/* Textarea expands with content */
[data-element="textarea"] {
min-height: calc(3 * 1.5em); /* 3 rows minimum */
max-height: calc(10 * 1.5em); /* 10 rows maximum */
overflow-y: auto; /* Scroll when max reached */
resize: vertical; /* Allow manual resize */
}Character Counter
<textarea data-element="textarea"
data-show-counter="true"
maxlength="500"
name="bio"></textarea>
<!-- Shows: 0/500 characters -->JavaScript API
const instance = ElementManager.getInstance(textareaEl);
// Force resize recalculation
instance.resize();
// Get current height
const height = instance.getHeight();Best Practices
1. ✅ Use Appropriate Element for Data Type
<!-- ✅ Colors -->
<input data-element="color" name="theme">
<!-- ✅ Price ranges -->
<input data-element="range" data-dual="true" name="budget">
<!-- ✅ Multiple categories -->
<input data-element="tags" name="categories">
<!-- ✅ Structured input -->
<input data-element="mask" data-mask="##/##/####" name="date">2. ✅ Set Sensible Limits
<!-- ✅ Good: Limit tags -->
<input data-element="tags" data-max-tags="5" name="keywords">
<!-- ✅ Good: Limit textarea -->
<textarea data-element="textarea" maxlength="1000" data-max-rows="15"></textarea>3. ✅ Provide Autocomplete for Tags
<!-- ✅ Good: User can discover existing tags -->
<input data-element="tags"
data-source="/api/tags"
name="skills">
<!-- ❌ Bad: User must guess tag names -->
<input data-element="tags" name="skills">4. ✅ Use tel Type for Phone Numbers
<!-- ✅ Good: Mobile keyboard shows numbers -->
<input type="tel"
data-element="tel"
name="phone">
<!-- ❌ Less ideal: Text keyboard on mobile -->
<input type="text"
data-element="mask"
data-mask="###-###-####"
name="phone">5. ✅ Consider Unmask on Submit
<!-- ✅ Good: Server receives clean number -->
<input data-element="mask"
data-mask="(###) ###-####"
data-unmask-on-submit="true"
name="phone">
<!-- Form submits: 1234567890 instead of (123) 456-7890 -->6. ✅ Use Dual Range for Filters
<!-- ✅ Good: Price filter with min-max -->
<input data-element="range"
data-dual="true"
min="0"
max="10000"
step="100"
data-format="฿{value}"
name="price">Related Documentation
- Form Elements Overview
- ElementFactory - Base class
- Text Elements - Text inputs
- Number Elements - Number inputs
- FormManager - Form-level validation