Block Reference — Permit Junction Website
This skill is the definitive reference for all blocks available in this project. It documents each block's content model, variants, CSS classes, decoration behavior, and authoring guidelines based on source code analysis and live preview testing.
Related Skills
- •da-content-authoring: How to create and edit content in the DA editor (UI interactions)
- •content-modeling: Design new block content models
- •building-blocks: Implement new blocks or modify existing ones
- •block-collection-and-party: Find reference implementations from the AEM Block Collection
When to Use This Skill
Use this skill when:
- •You need to know what blocks are available and how they work
- •You're authoring content and need the correct block structure
- •You want to understand a block's variants and configuration options
- •You're debugging why a block isn't rendering correctly
- •You need to know the content model contract between authors and code
Skip this skill when:
- •You're writing block code (use building-blocks)
- •You're designing a new content model from scratch (use content-modeling)
- •You're performing DA editor interactions (use da-content-authoring)
Block Inventory
| Block | Type | Auto-Blocked | DA Library | File |
|---|---|---|---|---|
| Hero | Standalone | No | Yes | blocks/hero/ |
| Card | Collection | No | Yes | blocks/card/ |
| Columns | Standalone | No | Yes | blocks/columns/ |
| Table | Standalone | No | Yes | blocks/table/ |
| Section Metadata | Configuration | No | Yes | blocks/section-metadata/ |
| Metadata | Configuration | No | Yes | (page-level, no block folder) |
| YouTube | Auto-Block | Yes | No | blocks/youtube/ |
| Advanced Tabs | Auto-Block | Yes | No | blocks/advanced-tabs/ |
| Header | Fragment | No | No | blocks/header/ |
| Footer | Fragment | No | No | blocks/footer/ |
| Fragment | Utility | Yes | No | blocks/fragment/ |
| Schedule | Utility | Yes | No | blocks/schedule/ |
DA Library blocks (available in the Library panel > Blocks tab): Hero, Card, Section Metadata, Columns, Metadata, Table.
Library block definitions are stored in docs/library/blocks/. The buttons library page documents button styling patterns (not a block, but a decoration pattern).
Hero Block
Type: Standalone
File: blocks/hero/hero.js, blocks/hero/hero.css
Purpose: Large banner/header area with optional background image or video and foreground text content.
Content Model
| Hero | |------| | [Background image or video — optional] | | [Heading, description, CTA links] |
- •The last row is always the foreground (text content)
- •The second-to-last row (if present) is the background (image or video)
- •A single-row hero has no background image
- •Background video: an mp4 link wrapping a picture element (the picture is the poster frame)
Variants
Specified in the title row: | Hero (variant1, variant2) |
| Variant | Effect |
|---|---|
center | Centers text horizontally and vertically |
small | Reduced height (180px min-height) |
large | Increased height (720px min-height) |
full | Full viewport height (100vh) |
light | Light color scheme (dark text on light background) |
dark | Dark color scheme (light text on dark background) |
stack | Stacked layout (no side-by-side at desktop) |
quiet-background | Applies blur effect to background |
Decoration Details
- •Foreground (last row) becomes
.hero-foregroundwith gradient overlay background - •Text containers within foreground get
.fg-textclass - •First heading gets class
hero-heading - •Element before the heading gets class
hero-detail - •First text column adds
hero-text-startto the.heroelement; subsequent columns addhero-text-end - •Background row (second-to-last, if present) becomes
.hero-backgroundwith absolute positioning - •If background contains a video link wrapping a picture, it creates a
<video>element with poster - •Default text color is
#fff(white) — requires dark background orlightvariant for readability
IMPORTANT: Hero Without Background Image
The hero block defaults to white text (color: #fff). Without a background image, the text is invisible on a white page background. The foreground gradient overlay (dark-to-transparent) is not sufficient for contrast without an image.
Fix: Always use the light variant when no background image is present:
- •
Hero (center, light)— centered with dark readable text - •
Hero (light)— left-aligned with dark readable text
The light variant sets color: var(--color-dark) and changes the gradient to light-based, making text readable on any background.
DA Library Templates
Two templates in docs/library/blocks/hero:
- •hero — With background image row + foreground text
- •hero (center) — Centered variant
Example Combinations
- •
Hero (light)— Simple text hero, no background, dark readable text - •
Hero (center, light)— Centered text, no background, dark readable text - •
Hero (center)— Centered text WITH background image (white text on dark image) - •
Hero (large, dark)— Full-width dark hero with large height - •
Hero (small, light)— Compact light hero - •
Hero (full, center)— Full-viewport centered hero with background image
Card Block
Type: Collection
File: blocks/card/card.js, blocks/card/card.css
Purpose: Repeating card items, each with optional image, content, and CTA.
Content Model
IMPORTANT: Each card is a SEPARATE block table. Do NOT put multiple cards as rows in a single card table. The grid layout for multiple cards comes from section-metadata (e.g., grid | 3), not from the card block itself.
Single-column card (no image):
| Card | |------| | [Bold title, description, CTA link] |
Two-column card (with image):
| Card | |------| | [Image] | [Heading, description, CTA link] |
Each card block table has exactly ONE data row containing the card's content. For a grid of 3 cards, you author 3 separate card block tables followed by section-metadata with grid | 3.
Variants
| Variant | Effect |
|---|---|
quiet | No shadow, no background, minimal styling |
center | Centered text alignment |
hash-aware | Appends current URL hash to CTA links |
Decoration Details
- •Each card row becomes a child div of the card block
- •Pictures are extracted into
.card-picture-container(60% aspect ratio) - •Text content goes into
.card-content-container - •The last paragraph containing a link becomes
.card-cta-container - •Default cards have
box-shadowand hover scale effect - •Quiet cards strip the shadow and background
Grid Layout
Cards are typically placed in a grid using section-metadata:
| Section Metadata | |-----------------| | style | center, container | | grid | 3 | | gap | l |
DA Library Templates
Template in docs/library/blocks/card (currently empty — use the structure above).
Columns Block
Type: Standalone (multi-column layout)
File: blocks/columns/columns.js, blocks/columns/columns.css
Purpose: Side-by-side column layout for content and images.
Content Model
| Columns | |---------| | [Column 1 content] | [Column 2 content] | | [Column 1 content] | [Column 2 content] |
- •Each row is a separate row in the layout
- •Each cell in a row is a column
- •The number of columns per row sets the
--child-countCSS variable
Variants
| Variant | Effect |
|---|---|
gap-xs | Extra small gap between columns |
gap-s | Small gap |
gap-m | Medium gap |
gap-l | Large gap |
gap-xl | Extra large gap |
gap-xxl | Extra extra large gap |
image-cover | Images fill their column with absolute positioning |
z-pattern | Odd rows swap column order (content/image alternates) |
align-top | Align column content to top instead of center |
Decoration Details
- •Each row gets
display: gridwithgrid-template-columns: repeat(var(--child-count), 1fr) - •Responsive: collapses to single column below 900px
- •
image-covervariant: picture containers getcover-imageclass, other content getscover-content - •
z-pattern: CSSdirection: rtlon odd rows swaps visual order
DA Library Templates
Template in docs/library/blocks/columns (currently empty — use the structure above).
Table Block
Type: Standalone
File: blocks/table/table.js, blocks/table/table.css
Purpose: Display structured tabular data with proper semantic HTML.
Content Model
| Table | |-------| | Header 1 | Header 2 | Header 3 | | Data 1 | Data 2 | Data 3 | | Data 4 | Data 5 | Data 6 |
- •First data row becomes
<thead>with<th>elements - •Remaining rows become
<tbody>with<td>elements - •Each data row gets class
table-content-row
Variants
None defined.
Decoration Details
- •Creates a semantic
<table>element inside the block - •First row:
<thead>><tr>><th>cells - •Remaining rows:
<tbody>><tr>><td>cells - •The table block wraps a table authored as a nested table inside the block table in DA
DA Library Templates
Template in docs/library/blocks/table — contains a nested table structure.
Authoring Note
In DA, the Table block is a table-within-a-table: the outer table is the block container (with "Table" title row), and the inner content is the actual data table. The DA library template handles this nesting correctly.
Section Metadata Block
Type: Configuration
File: blocks/section-metadata/section-metadata.js, blocks/section-metadata/section-metadata.css
Purpose: Configure the layout and appearance of the section it belongs to.
Content Model
| Section Metadata | |-----------------| | style | center, container | | grid | 3 | | gap | l | | spacing | xl | | background | color-token-purple-200 |
Always placed as the last block in a section (before the section break).
Configuration Keys
| Key | Values | Effect |
|---|---|---|
style | Comma-separated CSS classes (e.g., center, container) | Applied as classes to the section |
grid | 2, 3, 4, 5, 6 | Number of grid columns for child blocks |
gap | xs, s, m, l, xl, xxl | Gap between grid items |
spacing | xs, s, m, l, xl, xxl | Section padding (top and bottom) |
container | 2, 4, 6 | Container width constraint (in grid columns) |
layout | bento | Special bento grid layout with named areas |
background | Color token (e.g., color-token-purple-200) | Section background color |
background-color | Color token | Alternative to background for color |
background-image | Image | Background image for the section |
Decoration Details
- •Parses key-value pairs from the 2-column table
- •
stylevalues are split by comma and added as CSS classes to the parent section - •
gridsetsgrid-template-columns: repeat(N, 1fr)on the section - •
backgroundcreates a.section-backgrounddiv with absolute positioning and the specified color - •
background-imagecreates a.section-backgroundwith a picture element - •Exports
getColorScheme()andsetColorScheme()for light/dark detection - •The section-metadata block itself is hidden after decoration (
display: none)
DA Library Templates
Template in docs/library/blocks/section-metadata — includes all common keys.
Common Patterns
Card grid section:
| Section Metadata | |-----------------| | style | center, container | | grid | 3 | | gap | l | | spacing | xxl |
Colored background section:
| Section Metadata | |-----------------| | style | center | | spacing | xxl | | background | color-token-purple-200 |
Metadata Block
Type: Configuration (page-level) Purpose: Set page-level metadata (title, description, social image, template).
Content Model
| Metadata | |----------| | title | Page Title Here | | description | Meta description for SEO | | image | [image] | | template | template-name |
Placed at the very end of the page, outside any section.
Configuration Keys
| Key | Values | Effect |
|---|---|---|
title | Text | Page <title> and og:title |
description | Text | Meta description and og:description |
image | Image | og:image for social sharing |
template | Template name | Page template selection |
DA Library Templates
Template in docs/library/blocks/metadata (currently empty — use the structure above).
YouTube Block (Auto-Blocked)
Type: Auto-Block
File: blocks/youtube/youtube.js, blocks/youtube/youtube.css
Purpose: Embed YouTube videos with privacy-enhanced mode.
Content Model
No block table needed. Simply paste a YouTube URL as a link in default content:
https://www.youtube.com/watch?v=VIDEO_ID
The link is auto-detected by the linkBlocks configuration in scripts.js and converted to a YouTube embed block.
Auto-Blocking Trigger
From scripts.js:
{ youtube: 'https://www.youtube' }
Any link starting with https://www.youtube is auto-blocked.
Decoration Details
- •Extracts video ID from
?v=parameter or URL path - •Creates privacy-enhanced embed:
https://www.youtube-nocookie.com/embed/{id} - •Preserves URL parameters (except
v) - •Adds
rel=0parameter to disable related videos - •Lazy-loads via intersection observer (
scripts/utils/observer.js) - •16:9 aspect ratio via
padding-bottom: 56.25%
Authoring Note
To add a YouTube video in DA:
- •Type or paste the full YouTube URL
- •Select the URL text
- •Click "Edit link" and set the URL as the link target
- •The link will be auto-blocked on preview/publish
To prevent auto-blocking, append #_dnb to the URL.
Known Rendering Behavior
The YouTube embed lazy-loads via IntersectionObserver. The .video container has no min-height before the iframe loads, so it may appear as an invisible empty space until the user scrolls to it. This is expected behavior — the embed renders once it enters the viewport.
Advanced Tabs Block (Auto-Blocked)
Type: Auto-Block
File: blocks/advanced-tabs/advanced-tabs.js, blocks/advanced-tabs/advanced-tabs.css
Purpose: Tabbed content interface created from sections.
Content Model
This block is auto-blocked from a specific content structure. Authors create:
- •A section containing a
<ul>list with tab names - •Followed by sections (one per tab), each starting with an
<h2>heading matching a tab name
- Tab One - Tab Two - Tab Three --- ## Tab One [Content for tab one...] --- ## Tab Two [Content for tab two...] --- ## Tab Three [Content for tab three...]
Decoration Details
- •The
<ul>list becomes the tab button bar - •Each list item becomes a
<button>withrole="tab" - •Sibling sections become tab panels with
role="tabpanel" - •Active tab gets
is-activeclass; visible panel getsis-visible - •Click handlers toggle between tabs
- •First tab is active by default
- •ARIA attributes for accessibility (
aria-selected,aria-controls,aria-labelledby)
Authoring Note
The tab names in the <ul> list must correspond to the <h2> headings in the following sections. The number of list items should match the number of subsequent sections.
Header Block (Fragment)
Type: Fragment-based
File: blocks/header/header.js
Purpose: Site header with navigation, brand, and actions.
Content Source
Loaded automatically from /fragments/nav/header. Not authored inline on pages.
Structure
The header fragment has 3 sections:
- •Brand: Logo and site name
- •Navigation: Mega menu with nested lists
- •Actions: Color scheme toggle, language selector, mobile menu toggle
Decoration Details
- •Brand section: wraps in
.header-brand - •Nav section: creates
.header-navwith expandable mega menu - •Actions section:
.header-actionswith scheme toggle button, language button - •Mobile: hamburger toggle (
.header-toggle) shows/hides nav - •Mega menu items with child lists become expandable dropdowns
Footer Block (Fragment)
Type: Fragment-based
File: blocks/footer/footer.js
Purpose: Site footer with links and legal text.
Content Source
Loaded automatically from /fragments/nav/footer. Not authored inline on pages.
Structure
- •Last section = copyright
- •Second-to-last section = legal links
- •Additional sections for footer content (navigation, social links, etc.)
Fragment Block (Utility)
Type: Utility / Auto-Block
File: blocks/fragment/fragment.js
Purpose: Load and inline content from another page.
Auto-Blocking Trigger
From scripts.js:
{ fragment: '/fragments/' }
Any link with a path containing /fragments/ is auto-blocked as a fragment.
Usage
In default content, add a link to a fragment path:
/fragments/some-content
The fragment block fetches the HTML from that path, decorates it, and replaces the link with the fragment content.
Schedule Block (Utility)
Type: Utility / Auto-Block
File: blocks/schedule/schedule.js
Purpose: Time-based content scheduling.
Auto-Blocking Trigger
From scripts.js:
{ schedule: '/schedules/' }
Usage
Links to /schedules/ paths are auto-blocked. The block fetches JSON schedule data, finds the matching event by date range, and loads the corresponding fragment.
For non-production testing, set localStorage.setItem('aem-schedule', '2024-06-15T10:00:00') to simulate a specific date/time.
Button Styles (Not a Block)
Buttons are not a separate block — they are a decoration pattern applied to links based on surrounding markup. The ak.js framework auto-converts links to styled buttons.
Patterns
| Author Markup | CSS Class | Style |
|---|---|---|
***text*** (bold+italic) | .btn-accent | Accent/CTA button |
**text** (bold) | .btn-primary | Primary button |
*text* (italic) | .btn-secondary | Secondary button |
~~text~~ (strikethrough) | .btn-negative | Negative/danger button |
Any above + <u> (underline) | adds .btn-outline | Outline variant |
Button Groups
Multiple styled links in the same paragraph create a button group (.btn-group):
***Accent*** **Primary** *Secondary*
(Each word is a separate link with the respective formatting.)
Hash Modifiers
| Hash | Effect |
|---|---|
#_blank | Opens link in new tab |
#_dnt | Do not localize this link |
#_dnb | Do not auto-block this link |
DA Library Reference
The docs/library/blocks/buttons page contains comprehensive examples of all button patterns, including accent, primary, secondary, negative, outline variants, button groups, and inline links.
Auto-Blocking Configuration
Auto-blocking is configured in scripts/scripts.js via the linkBlocks array:
const linkBlocks = [
{ fragment: '/fragments/' },
{ schedule: '/schedules/' },
{ youtube: 'https://www.youtube' },
];
When a link in default content matches a pattern, it is automatically converted to the corresponding block. To prevent auto-blocking on a specific link, append #_dnb to the URL.
Self-Managed Style Blocks
Blocks listed in the components array in scripts.js manage their own CSS loading:
const components = ['fragment', 'schedule'];
These blocks skip automatic CSS loading by the framework.
DA Library Structure
The DA Library panel (accessible via the "Library" toolbar button) provides pre-built block templates for authors. Library definitions are stored in docs/library/blocks/:
docs/library/blocks/ buttons # Button pattern reference (not a block) card # Card block template columns # Columns block template hero # Hero block templates (default + center variant) metadata # Page metadata template section-metadata # Section metadata template table # Table block template (nested table structure)
Each library page contains one or more example block tables that authors can insert by clicking the block name in the Library panel. The block name must match the block title row exactly.
Library Block Templates Available
| Library Entry | Variants Included |
|---|---|
| Hero | hero, hero (center) |
| Card | (empty — needs template) |
| Columns | (empty — needs template) |
| Section Metadata | All common keys |
| Metadata | (empty — needs template) |
| Table | Nested table example |
| Buttons | All button patterns |
Key Authoring Rules
- •
Block title rows must be a single merged cell containing only the block name (and optional variants in parentheses). A title row with multiple cells will not be recognized as a block.
- •
Each card is a separate block table. Do NOT put multiple cards as rows in one table. For a grid of cards, author individual card tables and use section-metadata with
grid | Nto arrange them. - •
Section metadata goes last in a section, immediately before the section break (horizontal rule).
- •
Page metadata goes at the very end of the page, outside any section.
- •
Auto-blocked links are converted automatically — no block table needed. Just paste the URL as a link.
- •
Variants are specified in the title row in parentheses:
| Hero (center, large) | - •
Button styling comes from text formatting, not from a block. Bold = primary, bold+italic = accent, italic = secondary.
- •
Grid layouts require section-metadata — cards and other collection blocks don't grid themselves. Use
gridkey in section-metadata. - •
Maximum 4 cells per row in any block content model.
- •
Fragment blocks load external content — header and footer are fragments loaded from
/fragments/nav/. Custom fragments can be loaded from any/fragments/path. - •
Hero blocks need
lightvariant without a background image. The default white text is invisible on a white page. UseHero (light)orHero (center, light)for text-only heroes. - •
When pasting block HTML programmatically, use
colspan="N"on the title row<td>for any block with multi-column data rows (section-metadata, columns, metadata). ProseMirror normalizes column counts and will split title rows without colspan.