Accessible Form
A form demonstrating a11y best practices with proper headings, aria-labels, input validation, and CSS transitions.
Features Used
- a11y attributes
- Heading hierarchy
- CSS transitions
- Form handling
How to Run
npm install @constela/core @constela/runtimenpx constela run accessible-form.jsonSource Code
json
{
"version": "1.0",
"state": {
"name": {
"type": "string",
"initial": ""
},
"email": {
"type": "string",
"initial": ""
},
"submitted": {
"type": "boolean",
"initial": false
},
"error": {
"type": "string",
"initial": ""
}
},
"actions": [
{
"name": "updateName",
"steps": [
{
"do": "set",
"target": "name",
"value": {
"expr": "var",
"name": "value"
}
}
]
},
{
"name": "updateEmail",
"steps": [
{
"do": "set",
"target": "email",
"value": {
"expr": "var",
"name": "value"
}
}
]
},
{
"name": "submit",
"steps": [
{
"do": "if",
"condition": {
"expr": "bin",
"op": "==",
"left": {
"expr": "state",
"name": "name"
},
"right": {
"expr": "lit",
"value": ""
}
},
"then": [
{
"do": "set",
"target": "error",
"value": {
"expr": "lit",
"value": "Please fill in all fields."
}
}
],
"else": [
{
"do": "if",
"condition": {
"expr": "bin",
"op": "==",
"left": {
"expr": "state",
"name": "email"
},
"right": {
"expr": "lit",
"value": ""
}
},
"then": [
{
"do": "set",
"target": "error",
"value": {
"expr": "lit",
"value": "Please fill in all fields."
}
}
],
"else": [
{
"do": "set",
"target": "error",
"value": {
"expr": "lit",
"value": ""
}
},
{
"do": "set",
"target": "submitted",
"value": {
"expr": "lit",
"value": true
}
}
]
}
]
}
]
}
],
"view": {
"kind": "element",
"tag": "div",
"props": {
"style": {
"expr": "lit",
"value": "font-family: system-ui, sans-serif; padding: 24px; max-width: 480px;"
}
},
"children": [
{
"kind": "element",
"tag": "h1",
"props": {
"style": {
"expr": "lit",
"value": "margin: 0 0 4px 0; font-size: 24px;"
}
},
"children": [
{
"kind": "text",
"value": {
"expr": "lit",
"value": "Contact Us"
}
}
]
},
{
"kind": "element",
"tag": "h2",
"props": {
"style": {
"expr": "lit",
"value": "margin: 0 0 16px 0; font-size: 16px; color: #666; font-weight: normal;"
}
},
"children": [
{
"kind": "text",
"value": {
"expr": "lit",
"value": "Your Information"
}
}
]
},
{
"kind": "element",
"tag": "div",
"props": {
"style": {
"expr": "lit",
"value": "display: flex; flex-direction: column; gap: 12px; margin-bottom: 16px;"
}
},
"children": [
{
"kind": "element",
"tag": "input",
"props": {
"type": {
"expr": "lit",
"value": "text"
},
"aria-label": {
"expr": "lit",
"value": "Your name"
},
"placeholder": {
"expr": "lit",
"value": "Your name"
},
"value": {
"expr": "state",
"name": "name"
},
"onInput": {
"event": "input",
"action": "updateName"
},
"style": {
"expr": "lit",
"value": "padding: 8px 12px; border: 1px solid #ccc; border-radius: 6px; font-size: 14px;"
}
}
},
{
"kind": "element",
"tag": "input",
"props": {
"type": {
"expr": "lit",
"value": "email"
},
"aria-label": {
"expr": "lit",
"value": "Email address"
},
"placeholder": {
"expr": "lit",
"value": "Email address"
},
"value": {
"expr": "state",
"name": "email"
},
"onInput": {
"event": "input",
"action": "updateEmail"
},
"style": {
"expr": "lit",
"value": "padding: 8px 12px; border: 1px solid #ccc; border-radius: 6px; font-size: 14px;"
}
}
}
]
},
{
"kind": "element",
"tag": "button",
"props": {
"onClick": {
"event": "click",
"action": "submit"
},
"style": {
"expr": "lit",
"value": "padding: 10px 24px; background: #0070f3; color: white; border: none; border-radius: 6px; font-size: 14px; cursor: pointer;"
}
},
"children": [
{
"kind": "text",
"value": {
"expr": "lit",
"value": "Submit"
}
}
]
},
{
"kind": "if",
"condition": {
"expr": "bin",
"op": "!=",
"left": {
"expr": "state",
"name": "error"
},
"right": {
"expr": "lit",
"value": ""
}
},
"then": {
"kind": "element",
"tag": "div",
"props": {
"style": {
"expr": "lit",
"value": "margin-top: 16px; padding: 12px 16px; background: #ffebee; color: #c62828; border-radius: 6px; font-size: 14px;"
}
},
"children": [
{
"kind": "text",
"value": {
"expr": "state",
"name": "error"
}
}
]
}
},
{
"kind": "if",
"condition": {
"expr": "state",
"name": "submitted"
},
"then": {
"kind": "element",
"tag": "div",
"props": {
"style": {
"expr": "lit",
"value": "margin-top: 16px; padding: 12px 16px; background: #e8f5e9; color: #2e7d32; border-radius: 6px; font-size: 14px;"
}
},
"children": [
{
"kind": "text",
"value": {
"expr": "lit",
"value": "Thank you for your submission!"
}
}
]
},
"transition": {
"enter": "fade-enter",
"enterActive": "fade-enter-active",
"exit": "fade-exit",
"exitActive": "fade-exit-active",
"duration": 300
}
}
]
}
}