HeroWithForm and leads API
This document describes how HeroWithForm submits lead data, how formType maps to backend routes in BootcampHero/api.js, and how to wire pages such as docs/autoanalytics-new/book-a-demo.md.
Step-by-step: New form on a new product page
Use this when you add a new product (or a new route) that should show HeroWithForm and post to a leads API. You do not create a second form component; you wire formType and (if needed) one block of API code.
Part A — Backend agreement (do this first)
-
Confirm the HTTP contract with whoever owns the API:
- Full path pattern (e.g.
POST .../v1/leads/<slug>on local/dev/test andPOST .../api/v1/leads/<slug>on live, if that matches your server). - Request JSON fields. Today
HeroFormalways sends the same shape assubmitAemBuyerGuideForm:name,email,company,phoneNumber,message,consent,captchaToken,pageUrl. If the new product needs different fields, you must extendHeroForm.js(and possibly add a dedicated submit function) — that is outside the “same payload” path.
- Full path pattern (e.g.
-
Choose a stable
formTypestring (lowercase, hyphenated), e.g.my-product. This value will appear in page frontmatter and ingetHeroWithFormHandler.
Part B — Register a new formType in api.js (skip if an existing type already points to the right URL)
Only complete these when getHeroWithFormHandler does not yet list your product.
-
Add paths for every environment in
API_CONFIG(local,dev,test,live): add something likemyProductPath: '/v1/leads/my-product'for non-live and/api/v1/leads/my-productforlive, following the same pattern astrueMeasurePath/infracentralPath. -
Add an endpoint getter, e.g.
getMyProductApiEndpoint(siteConfig), mirroring existing getters:- If
siteConfig.customFields.myProductApiUrlis set → return it (full URL). - Else if
siteConfig.customFields.leadsApiUrlis set → return`${leadsApiUrl}/my-product`(slug must match backend). - Else →
`${config.baseUrl}${config.myProductPath}`usinggetEnvironment().
- If
-
Add a submit wrapper if the payload matches the shared hero payload:
submitMyProductFormcan delegate tosubmitAemBuyerGuideForm(formData, apiUrl)withapiUrldefaulted togetMyProductApiEndpoint(). -
Wire the switch: in
getHeroWithFormHandler, add acase 'my-product':returning{ endpoint: getMyProductApiEndpoint(siteConfig), submit: submitMyProductForm }. -
Optional —
docusaurus.config.js: exposemyProductApiUrlundercustomFieldsif you need a full-URL override per environment (same idea astrueMeasureApiUrl/infracentralApiUrl).
Part C — Product markdown (source of truth for copy and formType)
-
Create (or extend) a doc under the product’s docs tree, e.g.
docs/<product-slug>/book-a-demo.md. The first fenced frontmatter block for the hero should look like:---
component: HeroWithForm
formType: my-product
formHeading: Book a Free Demo
formId: <product>-book-a-demo-form
successMessage: Thank you! We will contact you shortly.
seo:
description: <page meta description>
--- -
Write the hero body below that frontmatter: headings, paragraphs, checkmark lines (
✓ ...) as supported byLeftContent. Add further---/component: ...sections for other blocks (stats, logos, etc.) if the page needs them. -
Uniqueness:
formIdmust be unique on the page if multiple heroes or anchors exist; use a product-specific id (step 8).
Part D — Route and generated JSON (product pages that use content-data)
Many products render from src/pages/product/<product>/*.mdx, which import src/content-data/<product>/<file>.json. If your new page follows that pattern:
-
Add or copy an MDX page under
src/pages/product/<product>/, e.g.book-a-demo.mdx:import sections from '@site/src/content-data/<product>/book-a-demo.json'(path must match the generator output).- Include
HeroWithFormincomponentMap(same pattern assrc/pages/product/autoanalytics-new/book-a-demo.mdx).
-
Regenerate section data so JSON matches the markdown. In this repo run
npm run generate:content(runsnode scripts/generate-section-data.mjs). -
Verify the generated file (e.g.
src/content-data/<product>/book-a-demo.json): the first section with"component": "HeroWithForm"should showcontent.formType(andformId) exactly as in the doc frontmatter. -
Restart or hard-refresh if the dev server does not pick up JSON changes.
Part E — Local verification
-
Run the site (
npm run start/npm run serve). Open the new product URL. -
Submit the form and inspect Network: the request URL must match the environment (e.g. local →
http://localhost:8000/api/v1/leads/<slug>when using default local config). If you useLEADS_API_URLorcustomFields, confirm the resolved URL. -
Fix env issues:
ERR_CONNECTION_REFUSEDonlocalhost:8000means no API is listening locally — pointLEADS_API_URLat a reachable dev API or run the backend.
Summary: New product page with an existing formType → do Part C (and E). New API slug → do Part A, B, then C and E.
Goals
- One hero + form UI for multiple products (no duplicate form components).
- Each page chooses which backend lead endpoint to use via
formType. - Environment-specific base URLs (local, dev, test, live) stay centralized in
api.js.
Component layout
| File | Role |
|---|---|
src/components/HeroWithForm/index.js | Layout: background, left column (LeftContent), right column (HeroForm). Reads formType, formId, formHeading, successMessage, downloadConfig from content / seo. |
src/components/HeroWithForm/HeroForm.js | Form UI, validation, reCAPTCHA, submit. Calls getHeroWithFormHandler(formType, siteConfig) to get endpoint + submit. |
src/components/HeroWithForm/LeftContent.js | Renders markdown-derived blocks (headings, paragraphs, lists). |
src/components/HeroWithForm/HeroWithForm.module.css | Section and form styling. |
Frontmatter and content
HeroWithForm expects the usual section shape: content includes hero copy and form settings.
Supported content fields (form-related)
| Field | Required | Default | Description |
|---|---|---|---|
formType | No | true-measure | Selects which lead API handler to use (see below). |
formId | No | true-measure | DOM id on the form card; used for accessibility hooks on the success dialog. Use a unique value if multiple heroes exist on one page. |
formHeading | No | (empty) | Shown above the form. Can also be set under seo.formHeading. |
successMessage | No | Generic thank-you | Message in the success dialog. |
filepath, file, format | No | (empty) | Optional post-submit asset download; if omitted, the form may resolve a download from resource-index.json when the current path matches a resource entry. |
Example: Autoanalytics New book-a-demo
Source: docs/autoanalytics-new/book-a-demo.md
---
component: HeroWithForm
formType: true-measure
formHeading: Book a Free Demo
formId: book-a-demo-form
successMessage: Thank you! Your demo request has been received. Our experts will contact you shortly.
seo:
description: Schedule a consultation with our experts
---
- Change
formTypeto switch the API (e.g.infracentral,aem-buyer-guide) without changing React code. formIdcan stay a stable marketing id (e.g.book-a-demo-form) as long as it is unique per page.
API layer: src/components/BootcampHero/api.js
Environment detection
getEnvironment() uses window.location.hostname to pick local, dev, test, or live, with a default of local.
Lead paths used by HeroWithForm
Per environment, API_CONFIG includes paths such as:
aemBuyerGuidePath:/v1/leads/aem-buyer-guide(local/dev/test) or/api/v1/leads/aem-buyer-guide(live).trueMeasurePath:/v1/leads/true-measureor/api/v1/leads/true-measure.infracentralPath:/v1/leads/infracentralor/api/v1/leads/infracentral.
Full URLs are built as baseUrl + path for the active environment.
getHeroWithFormHandler(formType, siteConfig)
This is the single switch used by HeroForm:
formType (case-insensitive) | Endpoint helper | Submit function |
|---|---|---|
true-measure (default) | getTrueMeasureApiEndpoint | submitTrueMeasureForm |
infracentral | getInfracentralApiEndpoint | submitInfracentralForm |
aem-buyer-guide | getAemBuyerGuideApiEndpoint | submitAemBuyerGuideForm |
submitTrueMeasureForm and submitInfracentralForm delegate to submitAemBuyerGuideForm with the resolved URL, so the JSON body is the same shape for these hero variants:
name,email,company,phoneNumber,message,consent,captchaToken,pageUrl
Optional overrides via docusaurus.config.js (customFields)
You can override endpoints without code changes when needed:
customFields key | Used by |
|---|---|
leadsApiUrl | Base like .../v1/leads; TrueMeasure appends /true-measure, Infracentral appends /infracentral. |
trueMeasureApiUrl | Full URL for TrueMeasure. |
infracentralApiUrl | Full URL for Infracentral. |
aemBuyerGuideApiUrl | Full URL for AEM Buyer’s Guide. |
captchaSiteKey | reCAPTCHA site key (see getCaptchaSiteKey). |
Product pages and generated JSON (reference)
Product MDX often imports src/content-data/.../*.json, e.g. src/pages/product/autoanalytics-new/book-a-demo.mdx → src/content-data/autoanalytics-new/book-a-demo.json. Editing docs/... alone does not update the live page until you regenerate JSON and reload; see Part D in the step-by-step above.
Related files (quick reference)
src/components/HeroWithForm/index.js— passesformTypeintoHeroForm.src/components/HeroWithForm/HeroForm.js—getHeroWithFormHandler+ submit.src/components/BootcampHero/api.js—API_CONFIG, getters,getHeroWithFormHandler, submit helpers.docs/autoanalytics-new/book-a-demo.md— example frontmatter forHeroWithForm.