cta-form
Copy beside a short form: a plain post, answered with no script.
{
"kind": "section",
"shell": {
"inset": "contained",
"density": "section",
"surface": "tint"
},
"block": {
"type": "cta-form",
"head": {
"eyebrow": "Listing request",
"title": "Tell Benchlist about it.",
"lede": "Six answers. The tools you name become the listing."
},
"action": "/list-a-bench/sent",
"fields": [
{
"name": "workshop",
"type": "text",
"label": "Workshop",
"placeholder": "Where the bench is"
},
{
"name": "email",
"type": "email",
"label": "Email",
"placeholder": "host@workshop.example"
},
{
"name": "city",
"type": "select",
"label": "City",
"options": [
"Duluth",
"Superior",
"Two Harbors",
"Cloquet",
"Another city"
]
},
{
"name": "kind",
"type": "select",
"label": "Kind",
"options": [
"Kiln room",
"Woodshop",
"Metal",
"Print",
"Textile",
"Jewelry",
"Other"
]
},
{
"name": "rate",
"type": "text",
"label": "Hourly rate",
"placeholder": "$20"
},
{
"name": "tools",
"type": "textarea",
"label": "Tools included",
"placeholder": "One tool per line"
}
],
"submit": "Send listing",
"note": "Benchlist takes 12 percent of each booking."
}
}
{
"title": "cta-form",
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "cta-form"
},
"head": {
"type": "object",
"properties": {
"eyebrow": {
"type": "string",
"minLength": 1,
"maxLength": 28
},
"title": {
"type": "string",
"minLength": 1,
"maxLength": 72
},
"lede": {
"type": "string",
"minLength": 1,
"maxLength": 300
},
"max": {
"type": "string",
"pattern": "^(none|\\d+(\\.\\d+)?(em|ch|px))$"
},
"ledeMax": {
"type": "string",
"pattern": "^(none|\\d+(\\.\\d+)?(em|ch|px))$"
},
"balance": {
"type": "boolean"
},
"scale": {
"type": "string",
"enum": [
"compact",
"large"
]
},
"tag": {
"type": "string",
"minLength": 1,
"maxLength": 8
},
"layout": {
"type": "string",
"enum": [
"split"
]
}
},
"required": [
"eyebrow"
],
"additionalProperties": false
},
"action": {
"type": "string",
"minLength": 1,
"maxLength": 160
},
"fields": {
"minItems": 1,
"maxItems": 8,
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"pattern": "^[a-z][a-z0-9-]{0,23}$"
},
"type": {
"type": "string",
"enum": [
"text",
"email",
"select",
"textarea"
]
},
"label": {
"type": "string",
"minLength": 1,
"maxLength": 16
},
"placeholder": {
"type": "string",
"minLength": 1,
"maxLength": 32
},
"options": {
"maxItems": 12,
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 32
}
}
},
"required": [
"name",
"type",
"label"
],
"additionalProperties": false
}
},
"submit": {
"type": "string",
"minLength": 1,
"maxLength": 24
},
"note": {
"type": "string",
"minLength": 1,
"maxLength": 80
}
},
"required": [
"type",
"head",
"action",
"fields",
"submit"
],
"additionalProperties": false
}When to use
Use a CTA form when the call is to send something: a question, an intake, an email address. It holds a head, one to eight fields, a submit label of 24 characters and a note of 80, and posts to its action with no script.
Ask only for what the answer needs. When the call is a button or a command, use closing.
Label each field with the noun the reader fills in, and use the note for when an answer comes.
closing: the call is a button or a command
The record
{
"kind": "section",
"shell": { "inset": "contained", "density": "section", "surface": "tint" },
"block": {
"type": "cta-form",
"head": { "eyebrow": "Listing request", "title": "Tell Benchlist about it.", "lede": "Six answers. The tools you name become the listing." },
"action": "/list-a-bench/sent",
"fields": [
{ "name": "workshop", "type": "text", "label": "Workshop", "placeholder": "Where the bench is" },
{ "name": "email", "type": "email", "label": "Email", "placeholder": "host@workshop.example" },
{
"name": "city",
"type": "select",
"label": "City",
"options": ["Duluth", "Superior", "Two Harbors", "Cloquet", "Another city"]
},
{
"name": "kind",
"type": "select",
"label": "Kind",
"options": ["Kiln room", "Woodshop", "Metal", "Print", "Textile", "Jewelry", "Other"]
},
{ "name": "rate", "type": "text", "label": "Hourly rate", "placeholder": "$20" },
{ "name": "tools", "type": "textarea", "label": "Tools included", "placeholder": "One tool per line" }
],
"submit": "Send listing",
"note": "Benchlist takes 12 percent of each booking."
}
}Smallest that parses
{
"type": "cta-form",
"head": { "eyebrow": "Listing request", "title": "Tell Benchlist about it." },
"action": "/list-a-bench/sent",
"fields": [
{ "name": "workshop", "type": "text", "label": "Workshop" }
],
"submit": "Send listing"
}Fields and bounds
From @mdxui/site@7.0.0-alpha.0. A count reads as min–max × item; a string bound is its maximum length in characters, and links its refusal.
| Prop | Type and bound | Required |
|---|---|---|
head | object | yes |
head.eyebrow | string ≤28 | yes |
head.title | string ≤72 | no |
head.lede | string ≤300 | no |
head.max | string (pattern) | no |
head.ledeMax | string (pattern) | no |
head.balance | boolean | no |
head.scale | "compact" | "large" | no |
head.tag | string ≤8 | no |
head.layout | "split" | no |
action | string ≤160 | yes |
fields | 1–8 × object | yes |
fields[].name | string (pattern) | yes |
fields[].type | "text" | "email" | "select" | "textarea" | yes |
fields[].label | string ≤16 | yes |
fields[].placeholder | string ≤32 | no |
fields[].options | 0–12 × string ≤32 | no |
submit | string ≤24 | yes |
note | string ≤80 | no |
Variants and counts
One layout, from 1 field to 8. Field names are lowercase, so the post reads cleanly.
One record in five Themes
Shells
In three Businesses
Carried by the contact Template. Seen on pages/benchlist/list-a-bench.json, section 2.
Do and do not
email."name": "Your email"Accessibility
| Check, on the exemplar render | Limit | Now | Pass |
|---|---|---|---|
| Skipped heading levels | 0 | 0 | yes |
| Unnamed nav landmarks | 0 | 0 of 0 | yes |
| Scroll regions a keyboard cannot reach | 0 | 0 of 0 | yes |
| Copy controls that announce the result | all | 0 of 0 | yes |
| Images and icons with no text alternative | 0 | 0 | yes |
Text pairs below AA across the 5 Themes and every scheme they emit: 5. See Render checks.
- Landmark The form sits in
main. It adds no landmark. - Heading level The head title renders as an
h2. Every field has alabel, and a status region announces the result. - Focus order Tab runs the fields in record order, then submit. A hidden trap field takes no focus.