# B2c Forms

> Build forms with validation in B2C Commerce using SFRA patterns. Use this skill whenever the user needs to create a storefront form (checkout, registration, profile edit, address, contact), define form fields in XML, handle form submission in a controller, add field validation rules, or render forms in ISML templates. Also use when they mention form XML definitions, server.forms.getForm, form gro…

- **Type:** Skill
- **Install:** `agentstack add skill-salesforcecommercecloud-b2c-developer-tooling-b2c-forms`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [SalesforceCommerceCloud](https://agentstack.voostack.com/s/salesforcecommercecloud)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** Apache-2.0
- **Upstream author:** [SalesforceCommerceCloud](https://github.com/SalesforceCommerceCloud)
- **Source:** https://github.com/SalesforceCommerceCloud/b2c-developer-tooling/tree/main/skills/b2c/skills/b2c-forms
- **Website:** https://salesforcecommercecloud.github.io/b2c-developer-tooling/

## Install

```sh
agentstack add skill-salesforcecommercecloud-b2c-developer-tooling-b2c-forms
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Forms Skill

This skill guides you through creating forms with validation in Salesforce B2C Commerce using the SFRA patterns.

## Overview

B2C Commerce forms consist of three parts:

1. **Form Definition** - XML file defining fields, validation, and actions
2. **Controller Logic** - Server-side form handling and processing
3. **Template** - ISML template rendering the HTML form

## File Location

Forms are defined in the cartridge's `forms` directory:

```
/my-cartridge
    /cartridge
        /forms
            /default              # Default locale
                profile.xml
                contact.xml
            /de_DE               # German-specific (optional)
                address.xml
```

## Form Definition (XML)

### Basic Structure

```xml

    

    

    

    
    

```

### Field Types

| Type | Description | HTML Input |
|------|-------------|------------|
| `string` | Text input | `` |
| `integer` | Whole number | `` |
| `number` | Decimal number | `` |
| `boolean` | Checkbox | `` |
| `date` | Date value | `` |

### Key Field Attributes

| Attribute | Purpose | Example |
|-----------|---------|---------|
| `formid` | Field identifier (required) | `formid="email"` |
| `label` | Resource key for label | `label="form.email.label"` |
| `type` | Data type (required) | `type="string"` |
| `mandatory` | Required field | `mandatory="true"` |
| `max-length` | Max string length | `max-length="100"` |
| `min-length` | Min string length | `min-length="8"` |
| `regexp` | Validation pattern | `regexp="^\d{5}$"` |

### Validation Error Messages

| Attribute | When Triggered |
|-----------|----------------|
| `missing-error` | Mandatory field is empty |
| `parse-error` | Value doesn't match regexp or type |
| `range-error` | Value outside min/max range |
| `value-error` | General validation failure |

See [Form XML Reference](references/FORM-XML.md) for complete field attributes, groups, lists, and validation patterns.

## Controller Logic (SFRA)

### Rendering a Form

```javascript
'use strict';

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

server.get('Show',
    csrfProtection.generateToken,
    function (req, res, next) {
        var form = server.forms.getForm('profile');
        form.clear();  // Reset previous values

        res.render('account/profile', {
            profileForm: form
        });
        next();
    }
);

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

### Processing Form Submission

```javascript
server.post('Submit',
    server.middleware.https,
    csrfProtection.validateAjaxRequest,
    function (req, res, next) {
        var form = server.forms.getForm('profile');

        if (!form.valid) {
            res.json({
                success: false,
                fields: getFormErrors(form)
            });
            return next();
        }

        // Access form values
        var email = form.email.value;
        var firstName = form.firstName.value;

        // Process and save data
        this.on('route:BeforeComplete', function () {
            var Transaction = require('dw/system/Transaction');
            Transaction.wrap(function () {
                customer.profile.email = email;
                customer.profile.firstName = firstName;
            });
        });

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

function getFormErrors(form) {
    var errors = {};
    Object.keys(form).forEach(function (key) {
        if (form[key] && form[key].error) {
            errors[key] = form[key].error;
        }
    });
    return errors;
}
```

### Prepopulating Forms

```javascript
server.get('Edit', function (req, res, next) {
    var form = server.forms.getForm('profile');
    form.clear();

    var profile = req.currentCustomer.profile;
    form.firstName.value = profile.firstName;
    form.lastName.value = profile.lastName;
    form.email.value = profile.email;

    res.render('account/editProfile', { profileForm: form });
    next();
});
```

## Template (ISML)

### Basic Form Template

```html

    
    

    
        
            ${Resource.msg('form.email.label', 'forms', null)}
        
        required
               maxlength="${pdict.profileForm.email.maxLength || 50}"/>
        
            ${pdict.profileForm.email.error}
        
    

    
        ${Resource.msg('button.submit', 'forms', null)}
    

```

## Localization

Form labels and errors use resource bundles:

**forms.properties:**
```properties
form.email.label=Email Address
form.email.required=Email is required
form.email.invalid=Please enter a valid email address
form.password.label=Password
button.submit=Submit
```

**forms_de_DE.properties:**
```properties
form.email.label=E-Mail-Adresse
form.email.required=E-Mail ist erforderlich
```

## Best Practices

1. **Always use CSRF protection** for form submissions
2. **Clear forms** before displaying to reset state
3. **Use resource keys** for labels and errors (localization)
4. **Validate server-side** even with client-side validation
5. **Use `route:BeforeComplete`** for database operations
6. **Return JSON** for AJAX form submissions

## Detailed Reference

For comprehensive form patterns:
- [Form XML Reference](references/FORM-XML.md) - Complete XML schema, validation patterns, and examples

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [SalesforceCommerceCloud](https://github.com/SalesforceCommerceCloud)
- **Source:** [SalesforceCommerceCloud/b2c-developer-tooling](https://github.com/SalesforceCommerceCloud/b2c-developer-tooling)
- **License:** Apache-2.0
- **Homepage:** https://salesforcecommercecloud.github.io/b2c-developer-tooling/

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-salesforcecommercecloud-b2c-developer-tooling-b2c-forms
- Seller: https://agentstack.voostack.com/s/salesforcecommercecloud
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
