CWDS Component Contribution Workflow
Overview
This guide documents the repeatable workflow for integrating a new CWDS (Commercial Web Design System) component into UXLab. Each component follows 7 steps, from Figma extraction through style guide publication.
package.json scripts) is for Nova/IVA components only. CWDS components use this separate manual workflow because they originate from the AEM production design system, not the Helium component library.Workflow Steps
Step 1: Extract from Figma
Use the Figma MCP tools to inspect the component's design tokens and structure.
# Get design context (layout, styles, code hints)
get_design_context({ nodeId: "<node-id>" })
# Get variable definitions (colors, spacing, typography values)
get_variable_defs({ nodeId: "<node-id>" })
Record the extracted values: font sizes (mobile + desktop), line heights, font weights, colors, spacing, and any responsive breakpoints. The AEM breakpoint is 985px.
Step 2: Add tokens to tokens.css
Add --cwds- namespaced custom properties to app/assets/css/cwds/tokens.css.
:root {
/* Mobile-first values */
--cwds-component-property: value;
}
@media (min-width: 985px) {
:root {
/* Desktop overrides */
--cwds-component-property: desktop-value;
}
}
Naming convention: --cwds-{component}-{property} (e.g., --cwds-h1-font-size, --cwds-card-padding).
Values must match public/resources/css/abvdesignsystem-themeless-styles.css exactly. When Figma and production CSS disagree, production CSS wins.
Step 3: Create utility classes
Add .cwds- prefixed classes to app/assets/css/cwds/typography.css (or create a new file like app/assets/css/cwds/cards.css).
.cwds-component-variant {
font-family: var(--cwds-font-family, Arial, Helvetica, sans-serif);
font-size: var(--cwds-component-font-size);
line-height: var(--cwds-component-line-height);
/* ... other properties using token vars */
}
If creating a new CSS file, import it from app/assets/css/cwds/index.css:
@import './tokens.css';
@import './typography.css';
@import './cards.css'; /* new component */
Responsive behavior is automatic — tokens.css updates custom properties at the 985px breakpoint, and utility classes inherit the changes.
Step 4: Build Vue component with dual mode
Create the component at app/components/cwds/{component}.vue.
Every CWDS component supports two rendering modes:
- AEM mode (
mode="aem"): Wraps content in<div class="ads__{section}">to trigger scoped styles from the production CSS. Uses AEM class names (.display-text,.claim-text, etc.). - Nuxt mode (
mode="nuxt"): Renders the semantic element with.cwds-{variant}utility classes. No wrapper div.
Required props pattern:
<script setup lang="ts">
interface CwdsComponentProps {
variant: 'variant-a' | 'variant-b'
as?: string // Override rendered HTML element
mode?: 'aem' | 'nuxt'
invert?: boolean // White text for dark backgrounds
}
const props = withDefaults(defineProps<CwdsComponentProps>(), {
mode: 'aem',
invert: false,
})
</script>
Both modes must produce visually identical output (same font-size, line-height, weight, color). Verify in browser.
Step 5: Extract AEM HTML reference
Create content/reference/cwds/aem-html/{component}.md with fenced code blocks showing the production AEM markup.
Each sample shows:
- Exact class names and DOM nesting from the production CSS
- The
[class*=ads__]scoping pattern - The
.invert-colormodifier if applicable - Any component-specific class patterns
Step 6: Write style guide page
Create content/reference/cwds/{component}.md with:
- Rendered examples using the Vue component via MDC syntax
- Variant name and description
- Font specs table (mobile and desktop: size / line-height / weight)
- Copyable code blocks for both AEM HTML and Nuxt component usage
- Link to Figma source
Add links to the new pages from content/reference/cwds/index.md.
Step 7: Register Code Connect
Map the Vue component to its Figma source using Code Connect MCP tools:
add_code_connect_map({
nodeId: "<component-node-id>",
componentName: "CwdsComponentName",
source: "app/components/cwds/component.vue",
label: "Vue"
})
Note: Code Connect only works with Figma component/state-group nodes, not regular frames. If the Figma source is a documentation frame, this step may need to be deferred until a proper component is created in Figma.
Checklist Template
Copy this checklist when starting a new CWDS component:
## CWDS Component: [Name]
- [ ] **Step 1**: Extract tokens from Figma (`get_design_context` + `get_variable_defs`)
- [ ] **Step 2**: Add `--cwds-` tokens to `app/assets/css/cwds/tokens.css`
- [ ] **Step 3**: Create `.cwds-` utility classes (new CSS file if needed, import from index.css)
- [ ] **Step 4**: Build `app/components/cwds/{name}.vue` with dual AEM/Nuxt mode
- [ ] **Step 5**: Extract AEM HTML reference → `content/reference/cwds/aem-html/{name}.md`
- [ ] **Step 6**: Write style guide page → `content/reference/cwds/{name}.md`
- [ ] **Step 7**: Register Code Connect mapping (if Figma component node exists)
- [ ] Typecheck passes (`pnpm run typecheck`)
- [ ] Browser-verified: both modes produce identical visual output
- [ ] Links added to `content/reference/cwds/index.md`
File Locations
| Purpose | Path |
|---|---|
| CSS tokens | app/assets/css/cwds/tokens.css |
| Utility classes | app/assets/css/cwds/{component}.css |
| CSS entry point | app/assets/css/cwds/index.css |
| Vue component | app/components/cwds/{component}.vue |
| AEM HTML reference | content/reference/cwds/aem-html/{component}.md |
| Style guide page | content/reference/cwds/{component}.md |
| CWDS index | content/reference/cwds/index.md |
| Production CSS | public/resources/css/abvdesignsystem-themeless-styles.css |
Key Conventions
- Token naming:
--cwds-{component}-{property}— always--cwds-prefix - Class naming:
.cwds-{variant}— always.cwds-prefix - AEM scoping:
[class*=ads__]— all AEM styles are scoped to this pattern - Breakpoint: 985px (matches AEM production, not standard Tailwind breakpoints)
- Font stack:
Arial, Helvetica, sans-serif(CWDS does not use custom web fonts) - Source of truth: Production CSS (
abvdesignsystem-themeless-styles.css) wins over Figma when values differ