@ea-lab/reactive-json-docs
Version:
Complete documentation for Reactive-JSON - Components, examples and LLM-parsable guides
573 lines (504 loc) • 19.5 kB
YAML
renderView:
- type: Markdown
content: |
# Input
The `Input` component provides a native HTML input field with automatic data synchronization, combining the simplicity of native HTML with the convenience of automatic data binding.
- type: blockquote
content:
- type: Markdown
content: |
**About specialized input components**
For common input types, you can use specialized wrapper components that pre-set the `inputType`:
- `TextField` (text), `EmailField` (email), `PasswordField` (password)
- `UrlField` (url), `SearchField` (search), `TelField` (tel)
- `NumberField` (number), `RangeField` (range)
- `DateField` (date), `TimeField` (time), `DateTimeField` (datetime-local)
- `MonthField` (month), `WeekField` (week)
- `ColorField` (color), `FileField` (file), `HiddenField` (hidden)
All these components use the same properties as `Input` but with a predefined input type.
Using convenience components makes it easier to override specific component types through reactive-json's [plugin system](/docs/advanced-concepts/plugins/plugin-system). For example, you can replace all `EmailField` components with a custom implementation while leaving other input types unchanged.
- type: button
attributes:
class: "btn btn-primary"
style:
marginTop: "10px"
content: "Show the convenience components override graph"
actions:
- what: setData
on: click
path: ~._showConvenienceComponentsOverride
value: true
- type: Modal
attributes:
class: "modal-xl"
showBoolPath: ~._showConvenienceComponentsOverride
headerTitle: "Convenience Components Override"
body:
- type: Mermaid
content: |
graph TB
subgraph "Convenience Components Override"
direction TB
subgraph "Application YAML"
AppYAML["Application YAML<br/>- type: EmailField<br/>- type: TextField<br/>- type: PasswordField"]
end
subgraph "Plugin Override Options"
direction TB
subgraph "Option 1: Override Specific Type"
CustomEmail["Custom EmailField<br/>• Enhanced validation<br/>• Company branding<br/>• Special features"]
DefaultText["Default TextField<br/>• Unchanged"]
DefaultPassword["Default PasswordField<br/>• Unchanged"]
end
subgraph "Option 2: Override Base Input"
CustomInput["Custom Input<br/>• Affects ALL types<br/>• Global changes"]
end
end
subgraph "Result"
direction TB
GranularControl["Granular Control<br/>Override only EmailField<br/>while keeping others default"]
GlobalControl["Global Control<br/>Override Input affects<br/>all convenience components"]
end
AppYAML --> CustomEmail
AppYAML --> DefaultText
AppYAML --> DefaultPassword
AppYAML --> CustomInput
CustomEmail --> GranularControl
DefaultText --> GranularControl
DefaultPassword --> GranularControl
CustomInput --> GlobalControl
end
subgraph "Plugin System Benefits"
Flexibility["Flexibility<br/>Target specific<br/>component types"]
Maintainability["Maintainability<br/>Override without<br/>changing YAML"]
Reusability["Reusability<br/>Share custom<br/>implementations"]
end
GranularControl --> Flexibility
GranularControl --> Maintainability
GranularControl --> Reusability
- type: Markdown
content: |
## Basic Syntax
```yaml
- type: Input
dataLocation: ~.fieldName
label: "Field Label:"
placeholder: "Enter value..."
inputType: "text"
inputAttributes:
required: true
attributes:
style:
marginBottom: "10px"
```
## Properties
- type: DefinitionList
content:
- term:
code: dataLocation
after: "(string, optional)"
details: "Path to bind the field value in the data context."
- term:
code: defaultFieldValue
after: "(string, optional)"
details: "Default value when no data is present."
- term:
code: label
after: "(string, optional)"
details: "Field label text (supports template evaluation)."
- term:
code: placeholder
after: "(string, optional)"
details: "Placeholder text (supports template evaluation)."
- term:
code: inputType
after: "(string, optional)"
details:
type: Markdown
content: "HTML input type (default: \"text\", supports template evaluation)."
- term:
code: attributes
after: "(object, optional)"
details: "Attributes applied to the container div (or merged with inputAttributes if no wrapper)."
- term:
code: inputAttributes
after: "(object, optional)"
details: "Attributes applied directly to the input element."
- term:
code: labelAttributes
after: "(object, optional)"
details: "Attributes applied to the label (htmlFor is automatically managed)."
- term:
code: forceWrapper
after: "(boolean, optional)"
details: "Forces the presence (true) or absence (false) of the wrapper div. If omitted, wrapper is automatic only if label is present."
- term:
code: actions
after: "(array, optional)"
details: "Actions to execute based on field state."
- type: Markdown
content: |
## Data Management
The component automatically synchronizes its value with the global data context. When `dataLocation` is used, the value is stored at the specified path. Without `dataLocation`, the value is stored in the template context using the component's `datafield`.
## Input Types
The `inputType` property supports all HTML5 input types:
- `text` (default): Standard text input
- `email`: Email validation
- `password`: Masked password input
- `url`: URL validation
- `tel`: Telephone number input
- `search`: Search input with clear button
- `number`: Numeric input
- `date`: Date picker
- And all other HTML5 types
## Wrapper Control
The component uses a flexible wrapper system that adapts based on the presence of a label and the `forceWrapper` property.
### Default Behavior
When no `forceWrapper` is specified, the component automatically determines whether to use a wrapper div. If a label is present, the component wraps both the label and input in a div container. If no label is present, the input is rendered directly without a wrapper.
### Explicit Control with `forceWrapper`
You can override the default behavior using the `forceWrapper` property. Setting `forceWrapper: true` will always create a wrapper div, even without a label. Setting `forceWrapper: false` will never create a wrapper, even when a label is present.
### Attribute Merging
When a wrapper is present, the `attributes` are applied to the div container and `inputAttributes` are applied to the input element. When no wrapper is present, both `attributes` and `inputAttributes` are merged and applied to the input element.
- type: button
attributes:
class: "btn btn-primary"
content: "Show the wrapper logic graph"
actions:
- what: setData
on: click
path: ~._showWrapperLogic
value: true
- type: Modal
attributes:
class: "modal-lg"
showBoolPath: ~._showWrapperLogic
headerTitle: "Wrapper Logic: Decision Tree for div Container Usage"
body:
- type: Mermaid
mermaidConfig:
themeVariables:
primaryColor: "transparent"
primaryBorderColor: "#666"
primaryTextColor: "#333"
lineColor: "#666"
secondaryColor: "transparent"
tertiaryColor: "transparent"
flowchart:
htmlLabels: true
nodeSpacing: 60
rankSpacing: 90
curve: basis
content: |
flowchart TD
A["⚙️ Input Component"] --> B{"🔧 forceWrapper<br/>specified?"}
B -->|✅ Yes| C{"🔧 forceWrapper<br/>=== true?"}
B -->|❌ No| D{"🏷️ Has label?"}
C -->|✅ Yes| E["📦 Use Wrapper<br/>= TRUE"]
C -->|❌ No| F["🚫 Use Wrapper<br/>= FALSE"]
D -->|✅ Yes| E
D -->|❌ No| F
E --> G["📦 Render with<br/>wrapper div"]
F --> H["🎯 Render without<br/>wrapper"]
G --> I["📦 attributes → div<br/>📝 inputAttributes → input"]
H --> J["🔄 Merge attributes<br/>with inputAttributes<br/>📝 All applied to input"]
I --> O{"🏷️ Has label?"}
O -->|✅ Yes| K["📄 HTML: div > label + input"]
O -->|❌ No| P["📄 HTML: div > input"]
J --> M{"🏷️ Has label?"}
M -->|✅ Yes| L["📄 HTML: label + input"]
M -->|❌ No| N["📄 HTML: input"]
- type: Markdown
content: |
### HTML Output Examples
**With label (automatic wrapper):**
- type: SyntaxHighlighter
language: "html"
content: |
<div>
<label htmlFor="input-abc123">Field Label:</label>
<input id="input-abc123" type="text" value="" />
</div>
- type: Markdown
content: |
**Without label (no wrapper):**
- type: SyntaxHighlighter
language: "html"
content: |
<input id="input-xyz789" type="text" value="" />
- type: Markdown
content: |
**Force wrapper without label:**
- type: SyntaxHighlighter
language: "html"
content: |
<div>
<input id="input-def456" type="text" value="" />
</div>
- type: Markdown
content: |
## Integrated vs Separated Labels
### Integrated Label (convenience)
```yaml
- type: Input
label: "My field:"
dataLocation: ~.value
```
**Advantages**: Simple, automatic accessibility (htmlFor)
**Limitations**: No conditional actions, limited styling
### Separated Label (full control)
```yaml
- type: label
content: "My field:"
attributes:
htmlFor: "my-input-id"
actions:
- what: setAttributeValue
when: ~.hasError
is: true
attribute: style.color
value: "red"
- type: Input
dataLocation: ~.value
forceWrapper: false
inputAttributes:
id: "my-input-id"
```
**Advantages**: Conditional actions, advanced styling, full control
**Disadvantages**: More verbose, manual accessibility management
**Recommendation**: Use the integrated label for most cases. Opt for separated label only if you need conditional actions or advanced styling.
- type: RjBuildDescriber
title: "Basic Example"
description: "Simple input with label and placeholder"
toDescribe:
renderView:
- type: Input
dataLocation: ~.username
label: "Username:"
placeholder: "Enter your username"
- type: div
content:
- "Current value: "
- type: strong
content: ~.username
data:
username: ""
- type: RjBuildDescriber
title: "Different Input Types"
description: "Input with various HTML5 types"
toDescribe:
renderView:
- type: Input
dataLocation: ~.email
label: "Email:"
placeholder: "user@example.com"
inputType: "email"
- type: Input
dataLocation: ~.password
label: "Password:"
placeholder: "Enter password"
inputType: "password"
- type: Input
dataLocation: ~.website
label: "Website:"
placeholder: "https://example.com"
inputType: "url"
- type: Input
dataLocation: ~.age
label: "Age:"
inputType: "number"
inputAttributes:
min: "0"
max: "120"
- type: div
attributes:
style:
marginTop: "20px"
padding: "10px"
borderRadius: "5px"
content:
- type: strong
content: "Current Values:"
- type: div
content:
- "Email: "
- ~.email
- type: div
content:
- "Password: "
- ~.password
- type: div
content:
- "Website: "
- ~.website
- type: div
content:
- "Age: "
- ~.age
data:
email: ""
password: ""
website: ""
age: ""
- type: RjBuildDescriber
title: "Custom Attributes"
description: "Input with custom attributes and pattern validation (format: ABC-123)"
toDescribe:
renderView:
- type: style
content: |
input[pattern]:valid {
border-color: #28a745;
box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25);
}
input[pattern]:invalid {
border-color: #dc3545;
box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25);
}
- type: Input
dataLocation: ~.productCode
label: "Product Code:"
placeholder: "ABC-123"
inputAttributes:
pattern: "[A-Z]{3}-[0-9]{3}"
title: "Format: ABC-123 (3 letters, dash, 3 numbers)"
maxLength: 7
attributes:
style:
marginBottom: "10px"
- type: div
content:
- "Product Code: "
- ~.productCode
data:
productCode: ""
- type: RjBuildDescriber
title: "Wrapper Control"
description: "Demonstration of different wrapper modes"
toDescribe:
renderView:
- type: Markdown
content: |
**1. No label → no wrapper automatically:**
- type: Input
dataLocation: ~.noWrapper
placeholder: "Input without wrapper"
attributes:
style:
border: "1px solid green"
marginBottom: "10px"
- type: Markdown
content: |
**2. With label → automatic wrapper:**
- type: Input
dataLocation: ~.autoWrapper
label: "With automatic wrapper:"
placeholder: "Input with wrapper"
attributes:
style:
marginBottom: "10px"
padding: "5px"
- type: Markdown
content: |
**3. Force wrapper even without label:**
- type: Input
dataLocation: ~.forceWrapper
placeholder: "Forced wrapper"
forceWrapper: true
attributes:
style:
border: "2px solid blue"
padding: "10px"
marginBottom: "10px"
borderRadius: "8px"
- type: Markdown
content: |
**4. No wrapper even with label:**
- type: Input
dataLocation: ~.noWrapperForced
label: "Label without wrapper:"
placeholder: "Input without forced wrapper"
forceWrapper: false
attributes:
style:
border: "2px solid red"
marginBottom: "10px"
- type: div
attributes:
style:
marginTop: "20px"
padding: "10px"
borderRadius: "5px"
content:
- type: strong
content: "Values:"
- type: div
content:
- "No wrapper: "
- ~.noWrapper
- type: div
content:
- "Auto wrapper: "
- ~.autoWrapper
- type: div
content:
- "Forced wrapper: "
- ~.forceWrapper
- type: div
content:
- "Forced no wrapper: "
- ~.noWrapperForced
data:
noWrapper: ""
autoWrapper: ""
forceWrapper: ""
noWrapperForced: ""
- type: RjBuildDescriber
title: "Custom Label Attributes"
description: "Customizing label styling"
toDescribe:
renderView:
- type: Input
dataLocation: ~.customLabel1
label: "Blue and bold label:"
placeholder: "Input with styled label"
labelAttributes:
style:
color: "blue"
fontWeight: "bold"
fontSize: "16px"
- type: Input
dataLocation: ~.customLabel2
label: "Label with CSS class:"
placeholder: "Input with class"
labelAttributes:
className: "custom-label"
style:
color: "#28a745"
textDecoration: "underline"
- type: div
content:
- "Value 1: "
- ~.customLabel1
- " | Value 2: "
- ~.customLabel2
data:
customLabel1: ""
customLabel2: ""
- type: Markdown
content: |
## Advantages
- **No external dependencies**: Works without any CSS framework
- **Full control**: Custom styling and behavior
- **Performance**: Lighter than component libraries
- **Accessibility**: Direct control over ARIA attributes, automatic htmlFor
- **Automatic synchronization**: Unlike raw HTML elements that require manual setData actions
- **Flexible wrapper**: Avoids unnecessary HTML when not needed
- **Flexibility**: Integrated label for convenience, separated for advanced control
## Limitations
- No built-in validation beyond HTML5 input type validation
- No support for input masking or formatting
- No built-in error message display
- Styling must be provided via external CSS or style attributes
- Template evaluation for `inputType` should return valid HTML input types
- Integrated label is limited: for conditional actions, prefer separated label
templates: {}
data: {}