Build a form¶
Briefing, not authority. (R) rule at linked source · (O) dated upstream fact · (P) procedure · (C) open work · (G) not established.
WHAT THIS MEANS IN DRUPAL¶
"Form" is four things. Pick the row:
| You need | Drupal calls it | Route |
|---|---|---|
| Editors edit a bundle | Entity form + form display, field groups | Config only (R) site-building §4a |
| Visitors submit data | Webform (contrib) | Adoption gate first (R) standard §13 |
Settings for a PROVEN_GAP module |
ConfigFormBase + config/schema |
Code, last rung (R) site-building §25 |
| Change an existing form | Form alter | ECA Form or OOP hook: C-FORM-ALTER |
Canvas page: place the form's block as a component (O, unverified).
OWNER¶
- Entity forms: core config (R) capability map.
- Visitor forms: no Bluefly record; not in the matrix (G); record work tracked on dam-16u (C). Drupal CMS's contact form is Webform + CAPTCHA + Honeypot; Webform 6.3.1: D10.3/D11, security-covered (O 2026-10-01).
- Core Contact: deprecated 11.4, removed 12.0 (O change record). Not a route.
PREREQUISITES¶
- (P) State the requirement, not the module (adoption A1).
- (P) Visitor form: adoption A1-A5 lands a matrix record
DISPOSITION=ADOPTbeforecomposer require. - (P) Settings form: a
PROVEN_GAPrecord exists.
DO THIS¶
- (P) Editorial: form display + field groups in §4a order (Core, Story, Relationships, Media, Discovery/SEO, Promotion, Governance); plain-English labels; export config.
- (P) Visitor: Webform config entity, exported; reusable form ships as a recipe (R) Rule I standard §3.
- (P) Post-submit automation: ECA model, not a subscriber (R) Rule E, how-we-build §12.
- (P) Settings:
ConfigFormBase, constructor DI, schema inconfig/schema/. - (P) Verify: submit as anon and authenticated; check stored result and a11y.
WATCH FOR¶
- CSRF: Form API adds and validates
form_token; non-form routes need_csrf_token(O drupal.org); Bluefly silent (G). #accesstakes anAccessResult, not a boolean; declare cache contexts; personalized parts via#lazy_builder, scalar args (R) standard §10 render rules.- Spam, PII retention: Webform can purge submissions (O); no Bluefly policy (G) C-FORM-POLICY.
- A11y is acceptance: labels, focus, keyboard, errors (R) site-building §29.
- Handler credentials: Key reference to 1Password only (R) secrets.
DO NOT¶
- Build a custom module, entity or table for submissions (R) Rule J.
- Post a JS form to a custom route: no Form API CSRF (O); new ingress needs proof (R) how-we-build §14.
- Put editorial copy in component source (R) site-building §4.
OWNERSHIP / CAN-SHOULD-MAY¶
- CAN: config UI, Drush, Tool Belt tools.
- SHOULD: site repo owns site forms, recipes reusable ones, theme presentation (R) site-building §17, §1, §16.
- MAY: install only after an adoption record adoption; machine mutations pass the Cedar gate (R) AGENTS.
DO NOT REDISCOVER¶
- Config before code, recipes over modules (R) Rules I, J; §4a section order; ECA owns automation (R) Rule E; core Contact is leaving core (O).
CONFLICTS¶
| ID | A | B | Resolution |
|---|---|---|---|
| C-CONTACT | dam-16u hypothesis: simple contact = core Contact | drupal.org: deprecated 11.4 | Follow upstream; no core Contact. |
| C-FORM-ALTER | BEST-PRACTICES §2.2: OOP form_alter |
Rule E, how-we-build §12: ECA first | Undecided. Proposed: ECA Form if event-condition-action, else OOP hook. Thomas decides. |
| C-WEBFORM-OWNER | Drupal CMS default: Webform | Bluefly matrix: no record | Run adoption first. |
| C-FORM-POLICY | Webform purge, spam add-ons exist | No Bluefly retention/spam rule | Decision needed. |
GO DEEPER¶
Anchored sources: frontmatter authority_sources. Expires last_verified + 30d.