Questions on React Components for Headless Adaptive forms | Community
Skip to main content
Level 3
March 11, 2026
Question

Questions on React Components for Headless Adaptive forms

  • March 11, 2026
  • 2 replies
  • 16 views

Hi all, 

We are working on delivering adaptive form as headless so a react spa can render it. We have used react starter kit as a base to do the POC. At this point, i have following questions while i try to wrap my head around these things and frame a picture. Any help in explaining would be great

  1. When i view https://www.npmjs.com/org/aemforms , i see a af-react-components and af-react-vanilla-components , how are they distinguished ? i see a latest commit into the af-react-components.
  2. I also noticed, af-custom-functions, how is this used ? i understand that we can include the same functions in our client libs and instead of loading them, the af-react-renderer would identify as they are included as dependency ?
  3. In order to use Scribble signature from Core components, we have been also provided with a custom theme, since this is headless, should i ask Adobe to include the theme into the react version, so it includes it as dependency ?
  4. Instead of using af-react-vanilla-components, in case react uses custom components, can they still re-use the JS functions that they load from AEM
  5. I have also noticed there is no Header and Footer component on React side, i remember reading JS embed approach of adaptive form strips of header and footer, that this stay valid for headless as well ? should we involve in adding headers and footers for headless ?

Thanks,

Abhishek

2 replies

AmitVishwakarma
Community Advisor
Community Advisor
March 11, 2026

Hi ​@kolluax 

1. @aemforms/af-react-components vs af-react-vanilla-components Use @aemforms/af-react-components + @aemforms/af-react-renderer – that's the main, recommended React library and what starter kits/docs use. Treat af-react-vanilla-components as an optional/alternate set, not the default.

2. @aemforms/af-custom-functions usage

It's just a JS library of reusable functions. For headless, anything you want to use in rules must be bundled into your React app (imported like a normal npm dependency). There's no auto‑loading from AEM clientlibs, so share code by using the same JS both in AEM (clientlib) and in your SPA.

3. Scribble signature + themes in headless

Headless Adaptive Forms send only JSON (structure + rules), not AEM themes. In React you implement the scribble/signature UI yourself (e.g. with a canvas/SignaturePad component) and style it in your own React theme. You can copy look‑and‑feel from the AEM theme, but the SPA owns the styling.

4. Using custom React components instead of af-react-vanilla-components

Yes, you can use your own components (Material UI, design system, etc.) and still reuse all the rule logic/custom functions. You map field types from the JSON to your components via the mappings object and connect them using useRuleEngine from @aemforms/af-react-renderer.

5. Header/footer in headless

Headless forms do not include header/footer or page chrome. That's consistent with the JS embed idea: the form is just the form; your SPA is responsible for global layout, header and footer.

 

Amit Vishwakarma - Adobe Commerce Champion 2025 | 16x Adobe certified | 4x Adobe SME
Adobe Employee
March 12, 2026

Hi ​@kolluax,

Thanks for sharing the details of your POC and the questions. Below is a consolidated response that you can use as a reference while continuing your React‑based headless implementation.

1. @aemforms/af-react-components vs @aemforms/af-react-vanilla-components

Within the @aemforms npm scope there are two main React component libraries:

  • @aemforms/af-react-components

    • React components based on Adobe React Spectrum.
    • These are the primary, fully supported reference components for Headless Adaptive Forms in React.
    • They are what the official React starter kit uses by default.[^starter]
  • @aemforms/af-react-vanilla-components

    • React components that are closer to plain HTML/“vanilla” controls, with minimal styling.
    • Intended as a simpler alternative and as sample code for building your own components or using other UI libraries.

In most production implementations customers:

  • Use @aemforms/af-react-components as the base, and
  • Gradually replace specific fields with their own React components via the mappings configuration.

You do not need to use af-react-vanilla-components unless you explicitly want the lighter, HTML‑like component set or to reuse some of the utilities exported from that package.

2. af-custom-functions – how it is meant to be used

The recommended pattern for custom business functions (used in rules and expressions) is:

  1. Implement them once in a dedicated JS module/package (similar to the internal af-custom-functions repo used by Adobe).
  2. Consume that same module:
    • From AEM (via clientlibs or dynamic ESM import), and
    • From your headless React app (regular npm import).
  3. Register the functions with the Headless runtime (af-core) so that the rule engine can invoke them.

This gives you a single source of truth for custom logic. You should not maintain two divergent copies of the same function (one in AEM clientlibs and one in the React SPA). Instead:

  • Treat your custom function library as a shared dependency.
  • Let AEM include it as a client library for headful/core‑component forms.
  • Let your React app import it as an npm dependency and register it with the headless runtime.

The form runtime does not “auto-detect” functions just because they exist in a clientlib; they need to be registered with the function runtime, which your React app typically does during initialization.[^custom_functions]

3. Scribble Signature (Core Components) in a headless / React setup

The Scribble Signature component is available as part of Adaptive Forms Core Components and is styled through a theme (for example, the Canvas or WKND themes). The important points for a headless React setup are:

  • The form JSON for a Scribble field can be rendered headless just like any other field, using @aemforms/af-core and @aemforms/af-react-renderer.[^arch]
  • The look and feel (including Scribble controls) is governed by the theme CSS, which is a front‑end asset independent of AEM.
  • For headless, the recommended approach is:
    • Use the same theme that your Core Component form uses (e.g. a theme based on aem-forms-theme-canvas).
    • Include the generated theme CSS in your React app bundle (for example via the @aemforms/af-canvas-theme npm package or a similar theme build.[^theme]]

In other words, you do not need Adobe to “bake the theme into the React renderer”. Instead, you:

  1. Author and configure the theme in AEM for your Core Component form.
  2. Build that theme as a standalone CSS asset.
  3. Import that CSS into your React SPA so that the Scribble field (and other components) are styled consistently for headful and headless channels.

If you share the exact field type / resource type used in your Scribble field’s JSON, we can help you define the precise React mapping for it as needed.

4. Using your own React components (instead of af-react-vanilla-components) while reusing JS logic

Yes, this is a fully supported and recommended pattern.

At a high level, your React setup will look like:

  • Logic and state:

    • @aemforms/af-core – core form model and rule engine.
    • @aemforms/af-react-renderer – React bindings and hooks (useRuleEngine) that connect the JSON model to your components.[^arch]
  • UI components:

    • Either use @aemforms/af-react-components (Spectrum) as a starting point, or
    • Define your own React components for each field type and wire them to the runtime.

The key mechanism is the mappings object passed into <AdaptiveForm>:

import {AdaptiveForm} from '@aemforms/af-react-renderer';
import {mappings as defaultMappings} from '@aemforms/af-react-components';
import MyTextField from './MyTextField';

const mappings = {
...defaultMappings,
'text-input': MyTextField, // replace default for all text-input fields
};

<AdaptiveForm formJson={formJSON} mappings={mappings} />;

Inside MyTextField, you reuse the same runtime hooks:

import {useRuleEngine} from '@aemforms/af-react-renderer';
import {FieldJson, State} from '@aemforms/af-core';

const MyTextField = (props: State<FieldJson>) => {
const [state, handlers] = useRuleEngine(props);
if (!state.visible) return null;

return (
<input
value={state.value ?? ''}
onChange={e => handlers.change(e.target.value)}
onBlur={handlers.blur}
/>
);
};

This approach gives you:

  • Full control over the UI (your design system, Material UI, etc.), and
  • Reuse of all the form logic (state, validation, rules, events) provided by the Web SDK.[^custom_components]

So you can absolutely skip af-react-vanilla-components if you prefer to build your own components or rely on another UI library.

5. Header and Footer in headless forms

Headless Adaptive Forms are intentionally focused on the form body. Global chrome like header and footer is expected to be owned by the host application (your React SPA, mobile app, etc.), not by the form JSON.

Internally, the current feature matrix shows that:

  • Header and Footer components are not implemented on the React/Spectrum runtime side, and
  • Themes are treated purely as front‑end assets to be consumed by the application, not embedded in the Web SDK.[^gaps]

This matches what you’ve seen:

  • There are no header/footer components in the React packages.
  • The recommended practice is:
    • Implement your site/app header and footer in your SPA layout (outside <AdaptiveForm>).
    • Use the form JSON only for the form itself, so the same form can be reused across multiple channels (web, mobile, chat) without carrying channel‑specific chrome.

The earlier AFv1 “JS embed” behavior (where header/footer were effectively stripped when embedding) still conceptually applies in the headless model: the SPA owns its overall layout; the headless runtime focuses on the form fields and their logic.

Summary for your POC

For your POC based on the React starter kit:

  1. Runtime: keep @aemforms/af-core and @aemforms/af-react-renderer as-is.
  2. Components: start from @aemforms/af-react-components and override individual field types with your own React components via mappings where needed.
  3. Custom functions: centralize them in one shared JS/TS package and consume it from both AEM and the SPA. Register them with the af-core runtime rather than duplicating logic.
  4. Scribble Signature: author it using Core Components in AEM, then include the same theme CSS in your React app. Only ask Adobe for help in making that theme consumable as an npm/webpack artifact if needed.
  5. Header & Footer: implement them in your React SPA, outside the <AdaptiveForm>; do not expect them from the headless JSON.

If you’d like, we can review one of your form JSON definitions and propose a concrete mappings.ts plus a skeleton for your shared custom-functions package.

Thanks
Pranay

[^starter]: Create and preview a Headless Form using a React apphttps://experienceleague.adobe.com/en/docs/experience-manager-headless-adaptive-forms/using/get-started/create-and-publish-a-headless-form
[^arch]: Headless adaptive forms architecturehttps://experienceleague.adobe.com/en/docs/experience-manager-headless-adaptive-forms/using/architecture
[^custom_components]: Use custom components to render a headless formhttps://experienceleague.adobe.com/en/docs/experience-manager-headless-adaptive-forms/using/get-started/developing-for-headless-forms-using-your-own-components