Boundary
Treat Macro as a content layer for labels and defaults — not as a form backend. Submission endpoints stay on your stack.
When to use form primitives
- Marketing or contact forms where editors change copy, placeholders, or default options.
- UI chrome that must stay editable (button labels next to inputs).
- Not for auth secrets, payment fields, or anything that must not be CMS-controlled.
Built-in types
| Name | Type | Description |
|---|---|---|
macro/attr-text | ATTR_TEXT | Text-like inputs and textarea — value, placeholder, label, … |
macro/select | SELECT | Select — selected value + options JSON |
macro/checkbox | CHECKBOX | Checkbox — checked, value, label |
macro/radio | RADIO | Single radio — checked, value, label |
macro/radio-group | RADIO_GROUP | Grouped radios — selected + options (when used as a group node) |
attr-text (inputs & textareas)
Covers text-like <input> types (including email, password, range, color) and <textarea>. Typical payload keys: value, placeholder, label, plus type-specific attrs the overlay exposes.
<label>
<span data-macro-key="contact.emailLabel">Email</span>
<input
name="email"
type="email"
required
data-macro-key="contact.email"
data-macro-type="attr-text"
/>
</label>
<textarea
name="message"
rows="5"
data-macro-key="contact.message"
data-macro-type="attr-text"
></textarea>Select
Payload: selected, options (JSON array of { value, label }), label. Editors change the selected value and can maintain option lists from the sidebar.
<label>
<span data-macro-key="contact.topicLabel">Topic</span>
<select name="topic" data-macro-key="contact.topic" data-macro-type="select">
<option value="sales">Sales</option>
<option value="support">Support</option>
</select>
</label>Checkbox & radio
<label>
<input
type="checkbox"
name="newsletter"
value="1"
data-macro-key="contact.newsletter"
data-macro-type="checkbox"
/>
<span data-macro-key="contact.newsletterLabel">Send me updates</span>
</label>Complete contact form example
<form class="contact" action="/api/contact" method="post">
<label>
<span data-macro-key="contact.nameLabel">Name</span>
<input name="name" data-macro-key="contact.name" data-macro-type="attr-text" />
</label>
<label>
<span data-macro-key="contact.emailLabel">Email</span>
<input
name="email"
type="email"
data-macro-key="contact.email"
data-macro-type="attr-text"
/>
</label>
<label>
<span data-macro-key="contact.messageLabel">Message</span>
<textarea
name="message"
data-macro-key="contact.message"
data-macro-type="attr-text"
></textarea>
</label>
<button type="submit" data-macro-key="contact.submit">Send message</button>
</form>Editor behavior
- Inline editors attach after login for attr-text, select, checkbox, and radio.
- Clicking a field selects it for the overlay; typing updates draft payload.
- Labels are often separate
macro/textnodes so structure stays semantic (<label>+ control).
Do
- Keep
name,action, andmethodin source control. - Give each editable control its own stable
data-macro-key. - Mark button labels as text primitives when editors should change CTA wording.
Don’t
- Don’t expect Macro to POST the form or validate server-side.
- Don’t put secrets or payment card fields behind Macro keys.
- Don’t reuse one key across multiple inputs.
See also Primitive reference and Editors · Form fields.