figma-code-agent 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/README.md +133 -0
  2. package/bin/install.js +328 -0
  3. package/knowledge/README.md +62 -0
  4. package/knowledge/css-strategy.md +973 -0
  5. package/knowledge/design-to-code-assets.md +855 -0
  6. package/knowledge/design-to-code-layout.md +929 -0
  7. package/knowledge/design-to-code-semantic.md +1085 -0
  8. package/knowledge/design-to-code-typography.md +1003 -0
  9. package/knowledge/design-to-code-visual.md +1145 -0
  10. package/knowledge/design-tokens-variables.md +1261 -0
  11. package/knowledge/design-tokens.md +960 -0
  12. package/knowledge/figma-api-devmode.md +894 -0
  13. package/knowledge/figma-api-plugin.md +920 -0
  14. package/knowledge/figma-api-rest.md +742 -0
  15. package/knowledge/figma-api-variables.md +848 -0
  16. package/knowledge/figma-api-webhooks.md +876 -0
  17. package/knowledge/payload-blocks.md +1184 -0
  18. package/knowledge/payload-figma-mapping.md +1210 -0
  19. package/knowledge/payload-visual-builder.md +1004 -0
  20. package/knowledge/plugin-architecture.md +1176 -0
  21. package/knowledge/plugin-best-practices.md +1206 -0
  22. package/knowledge/plugin-codegen.md +1313 -0
  23. package/package.json +31 -0
  24. package/skills/README.md +103 -0
  25. package/skills/audit-plugin/SKILL.md +244 -0
  26. package/skills/build-codegen-plugin/SKILL.md +279 -0
  27. package/skills/build-importer/SKILL.md +320 -0
  28. package/skills/build-plugin/SKILL.md +199 -0
  29. package/skills/build-token-pipeline/SKILL.md +363 -0
  30. package/skills/ref-html/SKILL.md +290 -0
  31. package/skills/ref-layout/SKILL.md +150 -0
  32. package/skills/ref-payload-block/SKILL.md +415 -0
  33. package/skills/ref-react/SKILL.md +222 -0
  34. package/skills/ref-tokens/SKILL.md +347 -0
@@ -0,0 +1,1184 @@
1
+ # PayloadCMS Block System
2
+
3
+ ## Purpose
4
+
5
+ Authoritative reference for the PayloadCMS block system. Documents the complete block architecture, field types, reusable field factories, block catalog, container nesting model, block rendering patterns, collection integration, Lexical editor configuration, and design token consumption. Encodes production patterns from a PayloadCMS 3.x + Next.js application with a visual builder plugin and container-first block architecture.
6
+
7
+ ## When to Use
8
+
9
+ Reference this module when you need to:
10
+
11
+ - Build new PayloadCMS blocks following established patterns
12
+ - Map Figma components to PayloadCMS block types (see `payload-figma-mapping.md`)
13
+ - Understand the tab-based field organization pattern used across all blocks
14
+ - Add or modify reusable field factories (imageTabs, linkGroup, layoutMeta)
15
+ - Configure the Container block's nesting, layout, and alignment options
16
+ - Extend the block rendering registry with new block types
17
+ - Understand how blocks consume design tokens via CSS Modules
18
+ - Configure Lexical rich text editors with restricted or full feature sets
19
+ - Integrate blocks into Pages or other collections via the `blocks` field type
20
+ - Debug block schema recursion or self-nesting issues
21
+
22
+ ---
23
+
24
+ ## Content
25
+
26
+ ### 1. Block Architecture Overview
27
+
28
+ PayloadCMS blocks are modular, reusable content units that editors compose into page layouts. Each block is a TypeScript object conforming to the `Block` type from `payload`, with a unique slug, a label, and a field array that defines the block's data schema.
29
+
30
+ #### Block Type Definition
31
+
32
+ ```typescript
33
+ import { Block } from 'payload'
34
+
35
+ export const Hero: Block = {
36
+ slug: 'hero',
37
+ fields: [
38
+ {
39
+ type: 'tabs',
40
+ tabs: [
41
+ { label: 'Content', name: 'content', fields: [...] },
42
+ { label: 'Media', fields: [...] },
43
+ { label: 'Settings', fields: [...] },
44
+ ],
45
+ },
46
+ ],
47
+ }
48
+ ```
49
+
50
+ Every block exports a `Block` constant from a `config.ts` file within its directory.
51
+
52
+ #### Slug Naming Convention
53
+
54
+ Block slugs use camelCase and are unique across the entire Payload configuration:
55
+
56
+ | Block | Slug |
57
+ |-------|------|
58
+ | Hero | `hero` |
59
+ | Card | `card` |
60
+ | Button | `button` |
61
+ | RichText | `richText` |
62
+ | Media | `media` |
63
+ | Video | `video` |
64
+ | Accordion | `accordion` |
65
+ | Stats | `stats` |
66
+ | Testimonial | `testimonial` |
67
+ | CallToAction | `callToAction` |
68
+ | StickyCTA | `stickyCTA` |
69
+ | SubNavigation | `subnavigation` |
70
+ | Container | `container` |
71
+ | Carousel | `carousel` |
72
+ | Tabs | `tabs` |
73
+ | Grid | `grid` |
74
+ | Form | `form` |
75
+ | Code | `code` |
76
+ | SubAccordion | `inneraccordion` |
77
+
78
+ #### Tab-Based Field Organization
79
+
80
+ All blocks organize their fields using the `tabs` field type. This provides a consistent editing experience where content, media, CTA actions, and settings are separated into distinct tab panels.
81
+
82
+ The standard tab pattern is:
83
+
84
+ 1. **Content tab** -- Primary content fields (richText, text, arrays)
85
+ 2. **Media/Image tab** -- Image upload via `imageFields` factory
86
+ 3. **CTA tab** -- Call-to-action links and buttons (when applicable)
87
+ 4. **Settings tab** -- Block configuration (className, layoutMeta, type variants)
88
+
89
+ Not every block has all four tabs. The minimum is two: a content-focused tab and a Settings tab.
90
+
91
+ #### Directory Structure
92
+
93
+ Blocks are organized by category under `src/admin/blocks/`:
94
+
95
+ ```
96
+ src/admin/blocks/
97
+ content/
98
+ Accordion/config.ts, layoutTab.ts, settingTab.ts, container.ts
99
+ Button/config.ts, ctaTab.ts, settingTab.ts
100
+ CallToAction/config.ts, settingTab.ts
101
+ Card/config.ts, ctaTab.ts, settingTab.ts
102
+ Hero/config.ts, settingTabs.ts
103
+ Media/config.ts, settingTab.ts
104
+ RichText/config.ts, settingTab.ts
105
+ StatCard/config.ts, settingTabs.ts
106
+ StickyCTA/config.ts, ctaTab.ts, settingTabs.ts
107
+ SubNavigation/config.ts, navItemTabs.ts, settingTabs.ts
108
+ Testimonial/config.ts, settingTabs.ts
109
+ Video/config.ts, customVideoblockField.ts, settingTabs.ts
110
+ layout/
111
+ Carousel/config.ts, carouselCard.ts, settingTabs.ts
112
+ Container/config.ts, settingTabs.ts
113
+ Grid/config.ts, settingTabs.ts
114
+ Tabs/config.ts, tabs.ts, container.ts, settingTabs.ts
115
+ FormEmbed/config.ts, settingTabs.ts
116
+ Code/config.ts, Component.tsx, Component.client.tsx, CopyButton.tsx
117
+ RenderBlocks.tsx
118
+ ```
119
+
120
+ Each block's `config.ts` is the entry point. Supporting files (settingTab, ctaTab, layoutTab) export individual `Field` or `Tab` definitions that are composed into the config.
121
+
122
+ ---
123
+
124
+ ### 2. Field Types Reference
125
+
126
+ PayloadCMS provides a rich set of field types. The following are commonly used across blocks.
127
+
128
+ #### Core Field Types
129
+
130
+ | Type | Purpose | Example Usage |
131
+ |------|---------|---------------|
132
+ | `text` | Single-line string input | Titles, labels, slugs, URLs, className |
133
+ | `richText` | Lexical editor for structured content | Block body content, descriptions |
134
+ | `upload` | File upload linked to a collection | Images via `relationTo: 'media'` |
135
+ | `relationship` | Reference to another document | Internal links to `pages`, modal references |
136
+ | `group` | Nested field container (no repetition) | Settings groups, CTA action groups |
137
+ | `array` | Repeatable list of field sets | Navigation items, carousel cards, tab items |
138
+ | `select` | Dropdown single-choice | HTML tag selection, link type, action type |
139
+ | `radio` | Radio button single-choice | Layout direction, impact level, CTA type |
140
+ | `checkbox` | Boolean toggle | Open in new tab, hidden, default state |
141
+ | `number` | Numeric input | Scroll offset, video dimensions, column count |
142
+ | `tabs` | Tabbed field organization | Every block's top-level field structure |
143
+ | `row` | Horizontal field layout | Side-by-side fields in admin UI |
144
+ | `blocks` | Nested block composition | Container children, accordion content |
145
+ | `code` | Code editor with syntax highlighting | Code block content |
146
+ | `json` | Raw JSON with custom component | Custom video field, form select |
147
+
148
+ #### The `tabs` Field Type
149
+
150
+ The `tabs` type is the primary organizational pattern. It creates a tabbed interface in the admin panel:
151
+
152
+ ```typescript
153
+ {
154
+ type: 'tabs',
155
+ tabs: [
156
+ {
157
+ label: 'Content', // Tab display name
158
+ name: 'content', // Optional: creates named data path
159
+ fields: [...] // Fields within this tab
160
+ },
161
+ {
162
+ label: 'Settings', // No name = fields stored at block root
163
+ fields: [...]
164
+ },
165
+ ],
166
+ }
167
+ ```
168
+
169
+ When a tab has a `name` property, its fields are nested under that path in the data (e.g., `block.content.richText`). When a tab has no `name`, fields are stored at the block root level.
170
+
171
+ #### The `blocks` Field Type (Nested Composition)
172
+
173
+ The `blocks` field enables block nesting -- a block can contain other blocks:
174
+
175
+ ```typescript
176
+ {
177
+ type: 'blocks',
178
+ name: 'blocks',
179
+ label: false,
180
+ blocks: [Card, RichText, Button, ...],
181
+ }
182
+ ```
183
+
184
+ This is used by Container, Accordion, and Tabs to hold child blocks. The `blocks` array defines which block types are allowed as children.
185
+
186
+ #### Conditional Field Display
187
+
188
+ Many fields use the `admin.condition` function to show/hide based on sibling field values:
189
+
190
+ ```typescript
191
+ {
192
+ name: 'externalLink',
193
+ type: 'text',
194
+ admin: {
195
+ condition: (data, siblingData) => siblingData.ctaAction === 'external',
196
+ },
197
+ }
198
+ ```
199
+
200
+ This pattern is used extensively for link type toggles (internal vs. external), CTA type toggles (button vs. link), and layout-specific fields (grid column count).
201
+
202
+ ---
203
+
204
+ ### 3. Reusable Field Factories
205
+
206
+ The recommended approach extracts common field patterns into reusable factories stored in `src/admin/fields/`.
207
+
208
+ #### `imageFields` (imageTabs.ts)
209
+
210
+ A group field that provides a standard image upload interface.
211
+
212
+ ```typescript
213
+ import { Field } from 'payload'
214
+
215
+ export const imageFields: Field = {
216
+ name: 'image',
217
+ type: 'group',
218
+ label: false,
219
+ fields: [
220
+ {
221
+ name: 'image',
222
+ label: 'Image',
223
+ type: 'upload',
224
+ relationTo: 'media',
225
+ },
226
+ ],
227
+ }
228
+ ```
229
+
230
+ **Usage:** Used in Hero (Media tab), Card (Image tab), Media (Image tab), CallToAction (Image tab), Testimonial (Image/Video tab), Grid (Image tab).
231
+
232
+ **Data path:** `block.image.image` (the group wraps the upload field).
233
+
234
+ #### `linkGroup()` (linkGroup.ts)
235
+
236
+ A factory function that generates an array field containing link items. Each link item uses the `link()` factory.
237
+
238
+ ```typescript
239
+ type LinkGroupType = (options?: {
240
+ appearances?: LinkAppearances[] | false
241
+ overrides?: Partial<ArrayField>
242
+ }) => Field
243
+
244
+ export const linkGroup: LinkGroupType = ({ appearances, overrides = {} } = {}) => {
245
+ const generatedLinkGroup: Field = {
246
+ name: 'links',
247
+ type: 'array',
248
+ fields: [link({ appearances })],
249
+ admin: { initCollapsed: true },
250
+ }
251
+ return deepMerge(generatedLinkGroup, overrides)
252
+ }
253
+ ```
254
+
255
+ **Parameters:**
256
+ - `appearances` -- Controls link appearance options (`'default' | 'outline'`). Pass `false` to hide appearance selector.
257
+ - `overrides` -- Deep-merged into the generated field. Used to customize `name`, `label`, `maxRows`.
258
+
259
+ **Usage in Hero:**
260
+ ```typescript
261
+ linkGroup({
262
+ overrides: { maxRows: 3, name: 'buttonGroup', label: 'Button' },
263
+ appearances: false,
264
+ })
265
+ ```
266
+
267
+ #### `link()` (link.ts)
268
+
269
+ A factory function that generates a single link group field with internal/external toggle, label, new tab checkbox, and optional appearance selector.
270
+
271
+ ```typescript
272
+ type LinkType = (options?: {
273
+ appearances?: LinkAppearances[] | false
274
+ disableLabel?: boolean
275
+ overrides?: Record<string, unknown>
276
+ }) => Field
277
+ ```
278
+
279
+ **Generated fields:**
280
+ - `type` (radio) -- `'reference'` (internal) or `'custom'` (external URL)
281
+ - `newTab` (checkbox) -- Open in new tab
282
+ - `reference` (relationship) -- Internal page link (shown when type is reference)
283
+ - `url` (text) -- External URL (shown when type is custom)
284
+ - `label` (text) -- Link display text (unless `disableLabel: true`)
285
+ - `appearance` (select) -- Visual style: `'default'` or `'outline'` (unless appearances is false)
286
+
287
+ #### `ClassName` (className/index.ts)
288
+
289
+ A text field for custom CSS class names.
290
+
291
+ ```typescript
292
+ export const ClassName: Field = {
293
+ name: 'className',
294
+ label: 'Custom Classname',
295
+ type: 'text',
296
+ admin: {
297
+ placeholder: 'e.g., custom-style',
298
+ description: 'Enter a class name for custom styling or interactivity.',
299
+ },
300
+ }
301
+ ```
302
+
303
+ **Usage:** Included in nearly every block's Settings tab. Enables editors to add custom CSS classes for per-instance styling or JavaScript hooks.
304
+
305
+ #### `LayoutMeta` (layoutMeta.ts)
306
+
307
+ A group field providing spacing and visibility controls for every block.
308
+
309
+ ```typescript
310
+ export const LayoutMeta: Field = {
311
+ name: 'layoutMeta',
312
+ type: 'group',
313
+ label: 'Layout',
314
+ fields: [
315
+ { type: 'row', fields: [marginTop, marginBottom] },
316
+ { type: 'row', fields: [paddingTop, paddingBottom] },
317
+ { name: 'hidden', type: 'checkbox', label: 'Hide this block', defaultValue: false },
318
+ ],
319
+ }
320
+ ```
321
+
322
+ **Spacing options** use Tailwind utility class values:
323
+
324
+ | Label | Margin Top | Margin Bottom | Padding Top | Padding Bottom |
325
+ |-------|-----------|---------------|-------------|----------------|
326
+ | None | `mt-0` | `mb-0` | `pt-0` | `pb-0` |
327
+ | XS (0.5rem) | `mt-2` | `mb-2` | `pt-2` | `pb-2` |
328
+ | SM (1rem) | `mt-4` | `mb-4` | `pt-4` | `pb-4` |
329
+ | MD (1.5rem) | `mt-6` | `mb-6` | `pt-6` | `pb-6` |
330
+ | LG (2rem) | `mt-8` | `mb-8` | `pt-8` | `pb-8` |
331
+ | XL (3rem) | `mt-12` | `mb-12` | `pt-12` | `pb-12` |
332
+ | 2XL (4rem) | `mt-16` | `mb-16` | `pt-16` | `pb-16` |
333
+
334
+ The values are stored as Tailwind class strings and applied directly to block wrapper elements at render time.
335
+
336
+ #### `defaultLexical` (defaultLexical.ts)
337
+
338
+ The global default Lexical editor configuration used by the Payload config's `editor` property. Provides a minimal feature set: Paragraph, Underline, Bold, Italic, and Link (with internal page references enabled).
339
+
340
+ ```typescript
341
+ export const defaultLexical: Config['editor'] = lexicalEditor({
342
+ features: () => [
343
+ ParagraphFeature(),
344
+ UnderlineFeature(),
345
+ BoldFeature(),
346
+ ItalicFeature(),
347
+ LinkFeature({ enabledCollections: ['pages'] }),
348
+ ],
349
+ })
350
+ ```
351
+
352
+ Individual blocks override this with their own `lexicalEditor()` configurations.
353
+
354
+ ---
355
+
356
+ ### 4. Block Catalog
357
+
358
+ The complete block type catalog, organized by category.
359
+
360
+ #### Content Blocks
361
+
362
+ **Hero** (`hero`)
363
+
364
+ | Property | Value |
365
+ |----------|-------|
366
+ | Slug | `hero` |
367
+ | Tabs | Content, Media, Settings |
368
+ | Content fields | `richText` (Lexical, full features), `buttonGroup` (linkGroup, max 3, no appearances) |
369
+ | Media fields | `imageFields` (upload to media collection) |
370
+ | Settings | `className`, `type` (radio: highImpact/mediumImpact/lowImpact), `layoutMeta` |
371
+ | CSS Module | `hero.module.css` |
372
+
373
+ The Hero block's `type` field controls visual impact level through CSS Module classes: `.heroContainerHigh` (min-height 400px), `.heroContainerMedium` (300px), `.heroContainerLow` (200px).
374
+
375
+ **Card** (`card`)
376
+
377
+ | Property | Value |
378
+ |----------|-------|
379
+ | Slug | `card` |
380
+ | Tabs | Content, CTA, Image, Settings |
381
+ | Content fields | `richText` (Lexical, restricted: no subscript, superscript, underline, strikethrough, code, link; adds FixedToolbarFeature) |
382
+ | CTA fields | `cta` group: `label` (text), `ctaAction` (select: internal/external), `internalLink` (relationship to pages), `externalLink` (text), `layout` (select: wrap-all/wrap-text-description/wrap-link-button) |
383
+ | Image fields | `imageFields` |
384
+ | Settings | `className`, `layoutMeta` |
385
+ | CSS Module | `card.module.css` |
386
+
387
+ The Card block uses a restricted Lexical editor that removes formatting features inappropriate for card content.
388
+
389
+ **Button** (`button`)
390
+
391
+ | Property | Value |
392
+ |----------|-------|
393
+ | Slug | `button` |
394
+ | Tabs | CTA, Settings |
395
+ | CTA fields | `cta` group: `label` (text), `type` (radio: button/link), `action` group (conditional: modal/scroll actions), `link` group (conditional: internal/external link) |
396
+ | Settings | `className`, `newTab` (checkbox), `layoutMeta` |
397
+ | CSS Module | `button.module.css` |
398
+
399
+ The Button block supports two behaviors: interactive button (modal trigger or scroll-to) and navigation link (internal or external).
400
+
401
+ **RichText** (`richText`)
402
+
403
+ | Property | Value |
404
+ |----------|-------|
405
+ | Slug | `richText` |
406
+ | Tabs | Content, Settings |
407
+ | Content fields | `richText` (Lexical, full default features) |
408
+ | Settings | `className`, `layoutMeta` |
409
+ | CSS Module | `richText.module.css` |
410
+
411
+ The simplest content block. Wraps a full-featured Lexical editor.
412
+
413
+ **Media** (`media`)
414
+
415
+ | Property | Value |
416
+ |----------|-------|
417
+ | Slug | `media` |
418
+ | Tabs | Image, Settings |
419
+ | Image fields | `imageFields` |
420
+ | Settings | `className`, `layoutMeta` |
421
+ | CSS Module | `media.module.css` |
422
+
423
+ A standalone image block for displaying a single media asset.
424
+
425
+ **Video** (`video`)
426
+
427
+ | Property | Value |
428
+ |----------|-------|
429
+ | Slug | `video` |
430
+ | Tabs | Content, Settings |
431
+ | Content fields | `customThumbnailField` (json with custom component: `customVideoBlockComponent`) |
432
+ | Settings | `className`, `videoSize` (radio: fixed/responsive), `height` (number, min 1000, conditional), `width` (number, min 1000, conditional), `layoutMeta` |
433
+ | CSS Module | `video.module.css` |
434
+
435
+ Uses a custom admin component for video upload/embed. Fixed size mode enables explicit height/width controls.
436
+
437
+ **Accordion** (`accordion`)
438
+
439
+ | Property | Value |
440
+ |----------|-------|
441
+ | Slug | `accordion` |
442
+ | Tabs | Layout, Settings |
443
+ | Layout fields | `title` (text, required), `htmlTag` (select: div/span/h2-h6, default h2), `content.blocks` (blocks: Button, CallToAction, Card, Form, Media, RichText, Stats, Tabs, Testimonial, Video, NestedContainer) |
444
+ | Settings | `customIcon` (upload to media), `defaultState` (radio: closed/open, default closed), `className`, `layoutMeta` |
445
+ | CSS Module | `accordion.module.css` |
446
+
447
+ The Accordion block nests other blocks within its expandable content area. It supports a custom toggle icon and can default to open or closed state.
448
+
449
+ **SubAccordion** (`inneraccordion`)
450
+
451
+ | Property | Value |
452
+ |----------|-------|
453
+ | Slug | `inneraccordion` |
454
+ | Tabs | Content, Settings |
455
+ | Purpose | A variant of Accordion used within nested containers. Provides the same accordion behavior but with a different slug to avoid schema conflicts. |
456
+
457
+ **Stats** (`stats`)
458
+
459
+ | Property | Value |
460
+ |----------|-------|
461
+ | Slug | `stats` |
462
+ | Tabs | Content, Settings |
463
+ | Content fields | `emphasis` (text -- the large number/metric), `title` (text), `richText` (Lexical, full features), `source` (text -- citation) |
464
+ | Settings | `className`, `layoutMeta` |
465
+ | CSS Module | `stats.module.css` |
466
+
467
+ Designed for displaying statistics or metrics with a prominent emphasis value.
468
+
469
+ **Testimonial** (`testimonial`)
470
+
471
+ | Property | Value |
472
+ |----------|-------|
473
+ | Slug | `testimonial` |
474
+ | Tabs | Content, Image/Video, Settings |
475
+ | Content fields | `richText` (Lexical, restricted: HeadingFeature h2-h5 + ParagraphFeature only), `author` (text), `authorDescription` (text) |
476
+ | Image/Video fields | `imageFields` |
477
+ | Settings | `className`, `layoutMeta` |
478
+ | CSS Module | `testimonial.module.css` |
479
+
480
+ The Testimonial block uses a heavily restricted Lexical editor with only heading and paragraph features.
481
+
482
+ **CallToAction** (`callToAction`)
483
+
484
+ | Property | Value |
485
+ |----------|-------|
486
+ | Slug | `callToAction` |
487
+ | Tabs | Content, Image, Settings |
488
+ | Content fields | `title` (text), `richText` (Lexical, full features) |
489
+ | Image fields | `imageFields` |
490
+ | Settings | `className`, `newTab` (checkbox), `layoutMeta` |
491
+ | CSS Module | `callToAction.module.css` |
492
+
493
+ A prominent banner-style block with title, description, and optional image.
494
+
495
+ **StickyCTA** (`stickyCTA`)
496
+
497
+ | Property | Value |
498
+ |----------|-------|
499
+ | Slug | `stickyCTA` |
500
+ | Tabs | Content, CTA, Settings |
501
+ | Content fields | `richText` (Lexical, heavily restricted: no heading, subscript, superscript, underline, strikethrough, code, link, upload, image, blockquote, relationship, lists; adds FixedToolbarFeature) |
502
+ | CTA fields | Same button/link CTA pattern as Button block |
503
+ | Settings | `className`, `layoutMeta` |
504
+ | CSS Module | `stickyCta.module.css` |
505
+
506
+ A fixed-position CTA bar. The Lexical editor is stripped to support only basic paragraph text.
507
+
508
+ **SubNavigation** (`subnavigation`)
509
+
510
+ | Property | Value |
511
+ |----------|-------|
512
+ | Slug | `subnavigation` |
513
+ | Tabs | Nav Items, Settings |
514
+ | Nav Items fields | `navItems` (array, maxRows 6): each item has `label` (text), `action` (select: internal/external), `internalLink` (relationship to pages, conditional), `externalLink` (text, conditional) |
515
+ | Settings | `className`, `layoutMeta` |
516
+ | CSS Module | `subNavigation.module.css` |
517
+
518
+ An in-page navigation bar with up to 6 items linking to internal pages or external URLs.
519
+
520
+ #### Layout Blocks
521
+
522
+ **Container** (`container`)
523
+
524
+ | Property | Value |
525
+ |----------|-------|
526
+ | Slug | `container` |
527
+ | Tabs | Layout, Settings |
528
+ | Layout fields | `content.blocks` (blocks: 14 block types, excludes Container itself) |
529
+ | Settings | `htmlTag`, `className`, `layout`, `columnsNumber`, `width`, `alignItems`, `justifyContent`, `gap`, `layoutMeta` |
530
+ | CSS Module | `container.module.css` |
531
+
532
+ The Container block is the primary layout mechanism. See Section 5 for a deep dive.
533
+
534
+ **Carousel** (`carousel`)
535
+
536
+ | Property | Value |
537
+ |----------|-------|
538
+ | Slug | `carousel` |
539
+ | Tabs | Layout, Settings |
540
+ | Layout fields | `richText` (Lexical, heading/intro), `carouselCard` (array of blocks: Card, Stats, Testimonial) |
541
+ | Settings | `className`, `layoutMeta` |
542
+ | CSS Module | (none specific -- uses container/card styles) |
543
+
544
+ Carousel items are stored as an array where each item contains a `blocks` field allowing Card, Stats, or Testimonial blocks.
545
+
546
+ **Tabs** (`tabs`)
547
+
548
+ | Property | Value |
549
+ |----------|-------|
550
+ | Slug | `tabs` |
551
+ | Tabs | Header, Tabs, Settings |
552
+ | Header fields | `richText` (Lexical, description/intro) |
553
+ | Tabs fields | `tabs` (array): each tab has `title` group (title text + auto-generated slug), `blocks` (blocks: NestedContainer, RichText, Button, CallToAction, Card, Form, Media, Stats, Testimonial, Video), and per-tab `settings` |
554
+ | Settings | `className`, `customIcon` (upload to media), `layoutMeta` |
555
+
556
+ The Tabs block auto-generates URL-safe slugs from tab titles via a `beforeChange` hook.
557
+
558
+ **Grid** (`grid`)
559
+
560
+ | Property | Value |
561
+ |----------|-------|
562
+ | Slug | `grid` |
563
+ | Tabs | Content, Image, Settings |
564
+ | Content fields | `title` (text), `richText` (Lexical, description) |
565
+ | Image fields | `imageFields` |
566
+ | Settings | `className` (no LayoutMeta) |
567
+
568
+ A simpler layout block for grid-based content with title, description, and image.
569
+
570
+ #### Utility Blocks
571
+
572
+ **Form** (`form`)
573
+
574
+ | Property | Value |
575
+ |----------|-------|
576
+ | Slug | `form` |
577
+ | Tabs | Content, Settings |
578
+ | Content fields | `customSelectField` (json with custom component for form selection), `submitAction` (select: displayMessage/redirectToPage), `redirectPage` (relationship to pages, conditional), `thankYouMessage` (richText, conditional) |
579
+ | Settings | `className`, `layoutMeta` |
580
+ | CSS Module | `formEmbed.module.css` |
581
+
582
+ Embeds an external form with configurable submit behavior.
583
+
584
+ **Code** (`code`)
585
+
586
+ | Property | Value |
587
+ |----------|-------|
588
+ | Slug | `code` |
589
+ | Fields | `language` (select: typescript/javascript/css), `code` (code field) |
590
+
591
+ The Code block does not use the tabs pattern. It has a flat field structure with a syntax-highlighted code editor. Includes custom React components for rendering and copy-to-clipboard functionality.
592
+
593
+ ---
594
+
595
+ ### 5. Container Block Deep Dive
596
+
597
+ The Container block is the most important block for Figma-to-PayloadCMS mapping because it mirrors Figma's Auto Layout concept -- a flexible box that arranges children in rows, columns, or grids.
598
+
599
+ #### Nesting Model
600
+
601
+ Container children are stored at the path `layout.content.blocks`:
602
+
603
+ ```
604
+ Container
605
+ └── tabs[0] (name: 'layout')
606
+ └── content (group)
607
+ └── blocks (blocks field)
608
+ ├── Block 1
609
+ ├── Block 2
610
+ └── Block 3
611
+ ```
612
+
613
+ The data path for accessing nested blocks is: `container.layout.content.blocks`.
614
+
615
+ #### Self-Nesting Prevention
616
+
617
+ The top-level Container block does NOT include itself in its allowed blocks list. This prevents infinite schema recursion that would break Payload's TypeScript type generation and database schema.
618
+
619
+ However, a `NestedContainer` variant exists that IS allowed inside:
620
+ - Accordion content
621
+ - Tabs content
622
+ - Other nested contexts (Tabs/container.ts)
623
+
624
+ The NestedContainer uses the same `container` slug and the same settings, but its `blocks` array excludes itself. This creates a maximum nesting depth of 2 levels: Container > NestedContainer (which cannot nest further Containers).
625
+
626
+ #### Layout Options
627
+
628
+ The Container's `layout` field controls the CSS display mode:
629
+
630
+ | Value | Label | CSS Result |
631
+ |-------|-------|------------|
632
+ | `col` | Column | `display: flex; flex-direction: column;` |
633
+ | `row` | Row | `display: flex; flex-direction: row;` |
634
+ | `grid` | Grid | `display: grid;` |
635
+
636
+ Default is `col` (vertical stacking).
637
+
638
+ When `grid` is selected, an additional `columnsNumber` field appears (max 12) that controls the CSS `grid-template-columns` value. A value of 1 or less triggers responsive auto-sizing.
639
+
640
+ #### Alignment Options
641
+
642
+ **alignItems** (cross-axis alignment):
643
+
644
+ | Label | Value (Tailwind) |
645
+ |-------|-----------------|
646
+ | Start | `items-start` |
647
+ | Center | `items-center` |
648
+ | End | `items-end` |
649
+ | Stretch | `items-stretch` |
650
+ | Baseline | `items-baseline` |
651
+
652
+ **justifyContent** (main-axis alignment):
653
+
654
+ | Label | Value (Tailwind) |
655
+ |-------|-----------------|
656
+ | Start | `justify-start` |
657
+ | Center | `justify-center` |
658
+ | End | `justify-end` |
659
+ | Space Between | `justify-between` |
660
+ | Space Around | `justify-around` |
661
+ | Space Evenly | `justify-evenly` |
662
+ | Stretch | `justify-stretch` |
663
+
664
+ These values are stored as Tailwind utility class strings and applied directly to the container element.
665
+
666
+ #### Gap Options
667
+
668
+ | Label | Value (Tailwind) | Actual Size |
669
+ |-------|-----------------|-------------|
670
+ | None | `gap-0` | 0 |
671
+ | Extra Small | `gap-1` | 0.25rem (4px) |
672
+ | Small | `gap-2` | 0.5rem (8px) |
673
+ | Medium | `gap-4` | 1rem (16px) |
674
+ | Large | `gap-6` | 1.5rem (24px) |
675
+ | Extra Large | `gap-8` | 2rem (32px) |
676
+ | XXL | `gap-12` | 3rem (48px) |
677
+ | XXXL | `gap-16` | 4rem (64px) |
678
+
679
+ Default gap is `gap-4` (1rem).
680
+
681
+ #### Width Constraints
682
+
683
+ | Label | Value | CSS Effect |
684
+ |-------|-------|------------|
685
+ | Full | `full` | No max-width constraint |
686
+ | Wide | `wide` | `max-width: 1400px; margin: 0 auto;` |
687
+ | Narrow | `narrow` | `max-width: 800px; margin: 0 auto;` |
688
+
689
+ Default width is `full`.
690
+
691
+ #### HTML Tag Selection
692
+
693
+ The Container supports semantic HTML element selection:
694
+
695
+ | Label | Value |
696
+ |-------|-------|
697
+ | `<div>` | `div` (default) |
698
+ | `<section>` | `section` |
699
+ | `<article>` | `article` |
700
+ | `<aside>` | `aside` |
701
+ | `<header>` | `header` |
702
+ | `<footer>` | `footer` |
703
+
704
+ This enables proper semantic HTML output without changing block behavior.
705
+
706
+ #### Container CSS Module
707
+
708
+ The container CSS Module (`container.module.css`) provides base styles and modifier classes:
709
+
710
+ ```css
711
+ .container {
712
+ gap: var(--token-spacing-md, 16px);
713
+ padding: var(--token-spacing-md, 16px);
714
+ }
715
+
716
+ .containerFlex { display: flex; }
717
+ .containerGrid { display: grid; }
718
+ .containerRow { flex-direction: row; }
719
+ .containerColumn { flex-direction: column; }
720
+ .containerNarrow { max-width: 800px; margin: 0 auto; }
721
+ .containerWide { max-width: 1400px; margin: 0 auto; }
722
+ .containerEmpty { color: var(--token-color-text-light, #9ca3af); font-style: italic; }
723
+ ```
724
+
725
+ At render time, the appropriate modifier classes are composed based on the block's settings values.
726
+
727
+ ---
728
+
729
+ ### 6. Block Rendering
730
+
731
+ The `RenderBlocks` component is the registry that maps block types to React components.
732
+
733
+ #### RenderBlocks Pattern
734
+
735
+ ```typescript
736
+ const blockComponents = {
737
+ Accordion,
738
+ Button,
739
+ Code,
740
+ Card,
741
+ Hero,
742
+ MediaBlock,
743
+ RichText,
744
+ Stats,
745
+ StickyCTA,
746
+ SubNavigationBlock,
747
+ Testimonial,
748
+ Video,
749
+ }
750
+
751
+ export const RenderBlocks: React.FC<{
752
+ blocks: NonNullable<Page['layout']>
753
+ }> = (props) => {
754
+ const { blocks } = props
755
+ const hasBlocks = blocks && Array.isArray(blocks) && blocks.length > 0
756
+
757
+ if (hasBlocks) {
758
+ return (
759
+ <Fragment>
760
+ {blocks.map((block, index) => {
761
+ const { blockType } = block
762
+ if (blockType && blockType in blockComponents) {
763
+ const Block = blockComponents[blockType]
764
+ if (Block) {
765
+ return (
766
+ <div key={index}>
767
+ <Block {...block} disableInnerContainer />
768
+ </div>
769
+ )
770
+ }
771
+ }
772
+ return null
773
+ })}
774
+ </Fragment>
775
+ )
776
+ }
777
+ return null
778
+ }
779
+ ```
780
+
781
+ #### How It Works
782
+
783
+ 1. Each block in the page's `layout.blocks` array has a `blockType` property matching its slug
784
+ 2. The `blockComponents` object maps block type names to their React component imports
785
+ 3. The renderer iterates over the blocks array, looks up the component, and renders it with the block's data spread as props
786
+ 4. The `disableInnerContainer` prop signals that the block should not render its own container wrapper (the parent already provides one)
787
+ 5. Each block gets a wrapper `<div>` with a key based on array index
788
+
789
+ #### CSS Module Application
790
+
791
+ Each block's React component imports its corresponding CSS Module from `src/styles/blocks/`:
792
+
793
+ ```typescript
794
+ // In Hero component
795
+ import styles from '@/styles/blocks/hero.module.css'
796
+
797
+ // Usage
798
+ <div className={styles.heroContainer}>
799
+ <div className={styles.heroContentArea}>
800
+ ...
801
+ </div>
802
+ </div>
803
+ ```
804
+
805
+ The CSS Modules are re-exported from `src/styles/blocks/index.ts` for convenient imports:
806
+
807
+ ```typescript
808
+ export { default as heroStyles } from './hero.module.css'
809
+ export { default as cardStyles } from './card.module.css'
810
+ export { default as containerStyles } from './container.module.css'
811
+ // ... all block styles
812
+ ```
813
+
814
+ #### Adding a New Block to the Registry
815
+
816
+ To add a new block type:
817
+
818
+ 1. Create the block config in `src/admin/blocks/{category}/{BlockName}/config.ts`
819
+ 2. Create the renderer component
820
+ 3. Create the CSS Module in `src/styles/blocks/{blockName}.module.css`
821
+ 4. Add the component to `blockComponents` in `RenderBlocks.tsx`
822
+ 5. Add the block to the Pages collection's `layout.blocks` array
823
+ 6. Add the CSS Module export to `src/styles/blocks/index.ts`
824
+
825
+ ---
826
+
827
+ ### 7. Collections Integration
828
+
829
+ #### Pages Collection
830
+
831
+ The Pages collection (`src/collections/Pages/index.ts`) is the primary consumer of blocks. Pages have a tabbed structure:
832
+
833
+ ```
834
+ Pages
835
+ ├── title (text, required)
836
+ ├── Layout tab (name: 'layout')
837
+ │ └── blocks (blocks field: 15 block types)
838
+ ├── Settings tab (name: 'settings')
839
+ │ ├── header (relationship to headers)
840
+ │ ├── footer (relationship to footers)
841
+ │ ├── projects (relationship to projects)
842
+ │ └── className
843
+ ├── SEO tab (name: 'meta')
844
+ │ └── MetaTitle, MetaImage, MetaDescription, Preview
845
+ └── slug (auto-generated from title)
846
+ ```
847
+
848
+ The blocks field at `layout.blocks` accepts all 15 top-level block types:
849
+
850
+ ```typescript
851
+ blocks: [
852
+ Accordion, Button, CallToAction, Carousel, Container,
853
+ Card, Form, Hero, MediaBlock, SubNavigationBlock,
854
+ RichText, Stats, StickyCTA, Tabs, Testimonial, Video,
855
+ ]
856
+ ```
857
+
858
+ Pages support:
859
+ - **Live preview** via `admin.livePreview.url`
860
+ - **Draft/publish** workflow via `versions.drafts`
861
+ - **Autosave** at 100ms intervals for live preview
862
+ - **Visual Builder** via a custom view at `/visual-builder`
863
+
864
+ #### Media Collection
865
+
866
+ The Media collection (`src/collections/Media.ts`) stores uploaded images:
867
+
868
+ ```typescript
869
+ export const Media: CollectionConfig = {
870
+ slug: 'media',
871
+ access: { read: () => true },
872
+ upload: {
873
+ imageSizes: [
874
+ { name: 'og', width: 1200, height: 630, formatOptions: { format: 'webp' } },
875
+ ],
876
+ adminThumbnail: 'og',
877
+ mimeTypes: ['image/*'],
878
+ },
879
+ fields: [
880
+ { name: 'alt', type: 'text', required: true },
881
+ ],
882
+ }
883
+ ```
884
+
885
+ Key details:
886
+ - Images are publicly readable (no auth required)
887
+ - Automatic WebP conversion for the `og` size (1200x630)
888
+ - Only image MIME types are accepted
889
+ - The `alt` field is required for accessibility
890
+ - Block image fields link to this collection via `relationTo: 'media'`
891
+
892
+ #### Relationship Patterns
893
+
894
+ Blocks reference other collections through three patterns:
895
+
896
+ 1. **Upload** -- Direct file reference: `type: 'upload', relationTo: 'media'`
897
+ 2. **Relationship (single)** -- Document reference: `type: 'relationship', relationTo: 'pages'`
898
+ 3. **Relationship (array)** -- Multi-collection: `relationTo: ['pages']` (can reference multiple collection types)
899
+
900
+ ---
901
+
902
+ ### 8. Lexical Editor Configuration
903
+
904
+ PayloadCMS uses the Lexical rich text editor. The recommended approach configures it at three levels.
905
+
906
+ #### Global Default
907
+
908
+ The `defaultLexical` configuration provides the baseline feature set for all richText fields that do not override the editor:
909
+
910
+ ```typescript
911
+ lexicalEditor({
912
+ features: () => [
913
+ ParagraphFeature(),
914
+ UnderlineFeature(),
915
+ BoldFeature(),
916
+ ItalicFeature(),
917
+ LinkFeature({ enabledCollections: ['pages'] }),
918
+ ],
919
+ })
920
+ ```
921
+
922
+ #### Full Feature Set
923
+
924
+ Most blocks use `lexicalEditor({})` which loads all default features:
925
+
926
+ ```typescript
927
+ // Hero, RichText, Stats, CallToAction, Carousel
928
+ { name: 'richText', type: 'richText', editor: lexicalEditor({}) }
929
+ ```
930
+
931
+ This includes heading, bold, italic, underline, strikethrough, subscript, superscript, code, link, upload, blockquote, lists, and more.
932
+
933
+ #### Restricted Feature Sets
934
+
935
+ Some blocks restrict the Lexical editor to appropriate features:
936
+
937
+ **Card** -- Removes subscript, superscript, underline, strikethrough, code, link. Adds FixedToolbarFeature:
938
+
939
+ ```typescript
940
+ lexicalEditor({
941
+ features: ({ defaultFeatures }) => [
942
+ ...defaultFeatures.filter(
943
+ (feature) => !['subscript', 'superscript', 'underline',
944
+ 'strikethrough', 'code', 'link'].includes(feature.key),
945
+ ),
946
+ FixedToolbarFeature(),
947
+ ],
948
+ })
949
+ ```
950
+
951
+ **StickyCTA** -- Heavily restricted. Removes heading, subscript, superscript, underline, strikethrough, code, link, upload, image, blockquote, relationship, all list types. Only paragraph and basic formatting remain:
952
+
953
+ ```typescript
954
+ lexicalEditor({
955
+ features: ({ defaultFeatures }) => [
956
+ ...defaultFeatures.filter(
957
+ (feature) => !['heading', 'subscript', 'superscript', 'underline',
958
+ 'strikethrough', 'code', 'link', 'upload', 'image',
959
+ 'blockquote', 'relationship', 'list', 'unorderedList',
960
+ 'orderedList', 'checklist'].includes(feature.key),
961
+ ),
962
+ FixedToolbarFeature(),
963
+ ],
964
+ })
965
+ ```
966
+
967
+ **Testimonial** -- Minimal: only headings (h2-h5) and paragraphs:
968
+
969
+ ```typescript
970
+ lexicalEditor({
971
+ features: () => [
972
+ HeadingFeature({ enabledHeadingSizes: ['h2', 'h3', 'h4', 'h5'] }),
973
+ ParagraphFeature(),
974
+ ],
975
+ })
976
+ ```
977
+
978
+ The pattern of restricting features per block ensures editors cannot add inappropriate content (e.g., no headings in a sticky CTA bar, no complex formatting in card text).
979
+
980
+ ---
981
+
982
+ ### 9. Token Integration
983
+
984
+ Blocks consume design tokens defined in `src/styles/tokens.css` through CSS Module rules that reference `--token-*` custom properties.
985
+
986
+ #### Token Categories in tokens.css
987
+
988
+ ```css
989
+ :root {
990
+ /* Typography */
991
+ --token-font-family: system-ui, -apple-system, ...;
992
+ --token-font-size-base: 18px;
993
+ --token-font-size-sm: 15px;
994
+ --token-font-size-lg: 20px;
995
+ --token-font-size-xl: 24px;
996
+ --token-font-size-2xl: 32px;
997
+ --token-font-size-3xl: 42px;
998
+ --token-font-size-4xl: 64px;
999
+
1000
+ /* Line Heights */
1001
+ --token-line-height-base: 32px;
1002
+ --token-line-height-sm: 24px;
1003
+ --token-line-height-tight: 1.2;
1004
+ --token-line-height-relaxed: 1.6;
1005
+
1006
+ /* Spacing */
1007
+ --token-spacing-xs: 4px;
1008
+ --token-spacing-sm: 8px;
1009
+ --token-spacing-md: 16px;
1010
+ --token-spacing-lg: 24px;
1011
+ --token-spacing-xl: 32px;
1012
+ --token-spacing-2xl: 48px;
1013
+ --token-spacing-3xl: 64px;
1014
+
1015
+ /* Colors */
1016
+ --token-color-text: #111827;
1017
+ --token-color-text-muted: #6b7280;
1018
+ --token-color-text-light: #9ca3af;
1019
+ --token-color-text-inverse: #ffffff;
1020
+ --token-color-bg: #ffffff;
1021
+ --token-color-bg-subtle: #f9fafb;
1022
+ --token-color-bg-muted: #f3f4f6;
1023
+ --token-color-bg-dark: #1e1e1e;
1024
+ --token-color-border: #e5e7eb;
1025
+ --token-color-border-strong: #d1d5db;
1026
+ --token-color-primary: #3b82f6;
1027
+ --token-color-primary-hover: #2563eb;
1028
+ --token-color-success: #10b981;
1029
+ --token-color-warning: #f59e0b;
1030
+ --token-color-error: #ef4444;
1031
+
1032
+ /* Border Radius */
1033
+ --token-radius-sm: 4px;
1034
+ --token-radius-md: 8px;
1035
+ --token-radius-lg: 12px;
1036
+ --token-radius-full: 9999px;
1037
+
1038
+ /* Shadows */
1039
+ --token-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
1040
+ --token-shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
1041
+ --token-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
1042
+
1043
+ /* Transitions */
1044
+ --token-transition-fast: 150ms ease;
1045
+ --token-transition-normal: 200ms ease;
1046
+ --token-transition-slow: 300ms ease;
1047
+ }
1048
+ ```
1049
+
1050
+ #### Import Pattern
1051
+
1052
+ CSS Modules import tokens.css to ensure custom properties are available:
1053
+
1054
+ ```css
1055
+ @import '../tokens.css';
1056
+
1057
+ .card {
1058
+ background-color: var(--token-color-bg, #ffffff);
1059
+ border-radius: var(--token-radius-lg, 12px);
1060
+ box-shadow: var(--token-shadow-sm, 0 1px 3px rgba(0, 0, 0, 0.1));
1061
+ }
1062
+ ```
1063
+
1064
+ #### Fallback Pattern
1065
+
1066
+ Every `var()` reference includes a fallback value that matches the token's default. This ensures blocks render correctly even if tokens.css is not loaded:
1067
+
1068
+ ```css
1069
+ /* Pattern: var(--token-{category}-{name}, {fallback-value}) */
1070
+ padding: var(--token-spacing-lg, 24px);
1071
+ color: var(--token-color-text, #111827);
1072
+ font-size: var(--token-font-size-2xl, 32px);
1073
+ ```
1074
+
1075
+ #### Token Consumption by Block
1076
+
1077
+ | Block | Token Categories Used |
1078
+ |-------|----------------------|
1079
+ | Hero | spacing, color (bg-subtle, bg-dark, text, text-inverse, primary), radius, font-size |
1080
+ | Card | spacing, color (bg, text, text-light, border, primary, text-inverse), radius, shadow, font-size |
1081
+ | Button | spacing, color (primary, primary-hover, text-inverse), radius, transition |
1082
+ | Accordion | spacing, color (bg, bg-subtle, text, text-muted, text-light, border, border-strong), radius |
1083
+ | Stats | spacing, color (bg, text, text-muted, text-light, primary, border), radius, font-size, line-height |
1084
+ | Testimonial | spacing, color (bg-subtle, text, text-muted, border), radius, font-size, line-height |
1085
+ | CallToAction | spacing, color (primary, text-inverse, text), radius, font-size |
1086
+ | Container | spacing, color (text-light) |
1087
+ | StickyCTA | spacing, color, radius |
1088
+ | SubNavigation | spacing, color, radius |
1089
+
1090
+ #### Tailwind Integration
1091
+
1092
+ The Container block stores alignment, gap, and spacing values as Tailwind utility class strings (e.g., `items-center`, `gap-4`, `mt-8`). These are applied directly to the rendered HTML element alongside CSS Module classes:
1093
+
1094
+ ```html
1095
+ <section class="flex flex-col items-center gap-4 mt-8 containerStyles.container">
1096
+ <!-- child blocks -->
1097
+ </section>
1098
+ ```
1099
+
1100
+ This demonstrates the three-layer CSS architecture in action:
1101
+ - **Layer 1 (Tailwind):** `flex flex-col items-center gap-4 mt-8`
1102
+ - **Layer 2 (Tokens):** Referenced within CSS Module via `var(--token-*)`
1103
+ - **Layer 3 (CSS Module):** `containerStyles.container` (scoped visual styles)
1104
+
1105
+ ---
1106
+
1107
+ ### 10. Select Options Reference
1108
+
1109
+ The `selectOptions.ts` file defines all shared option arrays used across blocks. This is the single source of truth for select and radio field options.
1110
+
1111
+ #### Layout Options
1112
+
1113
+ ```typescript
1114
+ export const layoutOptions = [
1115
+ { label: 'Column', value: 'col' },
1116
+ { label: 'Row', value: 'row' },
1117
+ { label: 'Grid', value: 'grid' },
1118
+ ]
1119
+ ```
1120
+
1121
+ #### HTML Tag Options
1122
+
1123
+ ```typescript
1124
+ export const htmlTagOptions = [
1125
+ { label: '<div>', value: 'div' },
1126
+ { label: '<section>', value: 'section' },
1127
+ { label: '<article>', value: 'article' },
1128
+ { label: '<aside>', value: 'aside' },
1129
+ { label: '<header>', value: 'header' },
1130
+ { label: '<footer>', value: 'footer' },
1131
+ ]
1132
+ ```
1133
+
1134
+ #### HTML Header Tag Options (for Accordion)
1135
+
1136
+ ```typescript
1137
+ export const htmlHeaderTagOptions = [
1138
+ { label: '<div>', value: 'div' },
1139
+ { label: '<span>', value: 'span' },
1140
+ { label: '<h2>', value: 'h2' },
1141
+ { label: '<h3>', value: 'h3' },
1142
+ { label: '<h4>', value: 'h4' },
1143
+ { label: '<h5>', value: 'h5' },
1144
+ { label: '<h6>', value: 'h6' },
1145
+ ]
1146
+ ```
1147
+
1148
+ #### Impact Options (for Hero)
1149
+
1150
+ ```typescript
1151
+ export const impactOptions = [
1152
+ { label: 'High Impact', value: 'highImpact' },
1153
+ { label: 'Medium Impact', value: 'mediumImpact' },
1154
+ { label: 'Low Impact', value: 'lowImpact' },
1155
+ ]
1156
+ ```
1157
+
1158
+ #### Width Options
1159
+
1160
+ ```typescript
1161
+ export const widthOptions = [
1162
+ { label: 'Full', value: 'full' },
1163
+ { label: 'Wide', value: 'wide' },
1164
+ { label: 'Narrow', value: 'narrow' },
1165
+ ]
1166
+ ```
1167
+
1168
+ ---
1169
+
1170
+ ## Cross-References
1171
+
1172
+ - **`css-strategy.md`** -- Three-layer CSS architecture (Tailwind + Custom Properties + CSS Modules). Defines how blocks combine Tailwind utility classes for layout, CSS custom properties for tokens, and CSS Modules for visual skin. The Container block's Tailwind class storage pattern is a direct implementation of Layer 1.
1173
+
1174
+ - **`design-tokens.md`** -- Token extraction pipeline, naming conventions, and promotion thresholds. The `--token-*` custom properties in `tokens.css` follow the naming patterns and extraction rules defined in this module.
1175
+
1176
+ - **`design-tokens-variables.md`** -- Figma Variables to CSS custom property bridge. Defines how Figma Variables resolve to the `--token-*` values consumed by block CSS Modules.
1177
+
1178
+ - **`design-to-code-semantic.md`** -- Semantic HTML element selection rules and BEM naming conventions. The Container block's `htmlTag` field and the block CSS Module BEM naming patterns (`.hero`, `.hero__title`, `.heroContainerHigh`) follow the conventions in this module.
1179
+
1180
+ - **`design-to-code-layout.md`** -- Auto Layout to Flexbox mapping. The Container block's layout, alignItems, justifyContent, and gap fields directly mirror the Figma Auto Layout properties documented in this module.
1181
+
1182
+ - **`payload-figma-mapping.md`** -- Figma component to PayloadCMS block mapping rules. Uses the block catalog and field definitions from this module to determine which Figma component becomes which block type and how properties map to fields.
1183
+
1184
+ - **`payload-visual-builder.md`** -- Visual Builder plugin architecture. Defines how blocks are edited visually within the Payload admin, including the Container's children path (`layout.content.blocks`) and the token aliasing pattern for CSS isolation.