# Sfcc Forms Development

> Guide for building, validating, securing, and persisting SFCC storefront forms (SFRA + SiteGenesis patterns). Use this when creating or troubleshooting form XML, controller handling, CSRF, and validation. Use when this capability is needed.

- Skill: `tomevault-io/sfcc-forms-development` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add tomevault-io/sfcc-forms-development`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tomevault-io/sfcc-forms-development/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: tomevault-io (https://skillmd.com/u/tomevault-io)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/tomevault-io/sfcc-forms-development

---


# SFCC Forms Development Skill

This skill guides you through implementing and troubleshooting the Salesforce B2C Commerce Forms Framework.

It covers:
- XML form definitions (schema, constraints, localization, reuse)
- Controller patterns (SFRA middleware, request handling, persistence)
- Secure validation (server-side first, CSRF/XSS protections)
- Migration guidance (SiteGenesis ➜ SFRA)

## When to Use

Use this skill when you need to:
- Create or modify a form definition in `cartridge/forms/**`.
- Render forms in ISML using the platform’s generated field metadata.
- Process POST submissions safely (CSRF, server-side validation, transactions).
- Add custom validation beyond XML constraints.
- Migrate legacy SiteGenesis form flows to SFRA.

## Quick Checklist (Production-Grade Forms)

```text
[ ] Form routes are POST-only and HTTPS-only
[ ] CSRF token is generated on GET and validated on POST
[ ] Server-side validation gate exists (do not trust client validation)
[ ] All string fields have max-length (DoS & storage safety)
[ ] Regex is conservative (avoid catastrophic backtracking)
[ ] Persistence happens inside Transaction.wrap
[ ] SFRA persistence is isolated in route:BeforeComplete where appropriate
[ ] Explicit mapping for writes (avoid mass assignment)
[ ] Form state cleared when appropriate (pre-render or after success)
[ ] User-provided values are output-encoded in ISML
```

## File Locations

### Form XML

Forms are defined per cartridge:

```
/my-cartridge
  /cartridge
    /forms
      /default
        profile.xml
        contact.xml
      /de_DE
        profile.xml
```

### Form Labels + Error Messages (Localization)

Resource bundles typically live in:

```
/my-cartridge
  /cartridge
    /templates
      /resources
        forms.properties
        forms_de_DE.properties
```

## Architecture Notes (Know the Moving Parts)

- Form XML is a strict server-side contract: it defines types, constraints, and errors.
- Form instances are stored in session scope (stateful across requests) and must be cleared deliberately.
- Client-side validation is UX; server-side validation is authoritative.

For deeper context and SFRA vs SiteGenesis architectural differences, see:
- [references/ARCHITECTURE-SGJC-SFRA.md](references/ARCHITECTURE-SGJC-SFRA.md)

## Form Definition (XML)

### Minimal Example

Keep examples small, but always include:
- strict types
- max-length for strings
- mandatory + missing-error where needed
- parse/range errors for format/constraint enforcement

```xml
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.demandware.com/xml/form/2008-04-19">
    <field formid="email" type="string"
           label="form.email.label"
           mandatory="true"
           max-length="254"
           regexp="^[^@\s]+@[^@\s]+\.[^@\s]+$"
           missing-error="form.email.required"
           parse-error="form.email.invalid"/>

    <action formid="submit" valid-form="true"/>
</form>
```

### Reuse and Modularity

Prefer `include` to avoid duplicating complex groups (e.g., an address group reused in checkout, profile, and gift registry).

See the cheat sheet:
- [references/FORM-XML-CHEATSHEET.md](references/FORM-XML-CHEATSHEET.md)

## Controller Patterns

### SFRA: Render Form (GET)

Goals:
- clear stale state when rendering an “empty” form
- generate a CSRF token

```javascript
'use strict';

var server = require('server');
var csrfProtection = require('*/cartridge/scripts/middleware/csrf');

server.get('Show',
    server.middleware.https,
    csrfProtection.generateToken,
    function (req, res, next) {
        var form = server.forms.getForm('contact');
        form.clear();

        res.render('forms/contact', {
            contactForm: form
        });
        next();
    }
);

module.exports = server.exports();
```

### SFRA: Handle Submission (POST)

Goals:
- validate CSRF first
- gate all business logic on `form.valid`
- isolate DB writes inside `Transaction.wrap`
- prefer `route:BeforeComplete` for persistence to keep transaction boundaries tight

```javascript
'use strict';

var server = require('server');
var Transaction = require('dw/system/Transaction');
var csrfProtection = require('*/cartridge/scripts/middleware/csrf');

server.post('Submit',
    server.middleware.https,
    csrfProtection.validateRequest,
    function (req, res, next) {
        var form = server.forms.getForm('contact');

        if (!form.valid) {
            // SFRA base commonly provides a helper like */cartridge/scripts/formErrors.
            // Prefer using it when available.
            res.json({
                success: false,
                fieldErrors: getFormErrorsSafe(form)
            });
            return next();
        }

        var email = form.email.value;
        var message = form.message && form.message.value;

        this.on('route:BeforeComplete', function () {
            Transaction.wrap(function () {
                // Persist explicitly (no mass assignment)
                // e.g. save a Custom Object, update profile, create a case, etc.
                // Keep only assignments inside the transaction.
            });

            form.clear();
        });

        res.json({ success: true });
        next();
    }
);

function getFormErrorsSafe(form) {
    try {
        var formErrors = require('*/cartridge/scripts/formErrors');
        if (formErrors && typeof formErrors.getFormErrors === 'function') {
            return formErrors.getFormErrors(form);
        }
    } catch (e) {
        // Optional dependency; fall back if not present.
    }
    return {};
}

module.exports = server.exports();
```

Notes:
- Use `csrfProtection.validateAjaxRequest` if your route expects AJAX conventions.
- Keep transactions short: no remote API calls, no heavy computation inside `Transaction.wrap`.

### SiteGenesis (SGJC): Key Differences

- Form is typically accessed via `app.getForm('id')` and rendered via `pdict.CurrentForms`.
- Templates must use generated `htmlName` (SiteGenesis uses `dwfrm_` prefixes + session-specific IDs).
- CSRF is often handled manually via `dw.web.CSRFProtection`.

Use this for migration and pitfalls:
- [references/ARCHITECTURE-SGJC-SFRA.md](references/ARCHITECTURE-SGJC-SFRA.md)

## ISML Rendering Rules

### Always Use Generated Field Metadata

- Prefer `field.htmlName` over hardcoded names.
- Use server-provided `pdict.csrf.*` when using SFRA CSRF middleware.

Typical SFRA token:

```html
<input type="hidden" name="${pdict.csrf.tokenName}" value="${pdict.csrf.token}" />
```

### XSS Safety

When outputting user-provided values, ensure the context is encoded (default output encoding is usually safe, but be deliberate):

```html
<isprint value="${pdict.contactForm.email.value}" encoding="htmlcontent" />
```

## Custom Validation

Use custom validation for business rules that XML cannot express (uniqueness checks, cross-field constraints, etc.).

Patterns:
- Field-level: invalidate a specific field.
- Group-level: invalidate the group for cross-field rules.
- Form-level: invalidate the form for global errors.

Keep custom validation server-side. Client-side validation is optional and must never be the security gate.

## Related Skills

- `sfcc-security` (CSRF, XSS, input validation)
- `sfcc-sfra-controllers` (middleware patterns, response handling)
- `sfcc-isml-development` (safe output encoding, template constraints)
- `sfcc-localization` (resource bundles, locale fallback)

## References

- [references/FORM-XML-CHEATSHEET.md](references/FORM-XML-CHEATSHEET.md)
- [references/ARCHITECTURE-SGJC-SFRA.md](references/ARCHITECTURE-SGJC-SFRA.md)

---
> Converted and distributed by [TomeVault](https://tomevault.io/claim/taurgis) — claim your Tome and manage your conversions.
<!-- tomevault:4.0:skill_md:2026-04-11 -->

