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());
});
tagsInput.addEventListener('tags:add', (e) => {
console.log('Added:', e.detail.tag);
});
tagsInput.addEventListener('tags:remove', (e) => {
console.log('Removed:', e.detail.tag);
});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