@undrr/undrr-mangrove 2.0.0 → 2.0.1

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 (175) hide show
  1. package/README.md +9 -5
  2. package/components/BookCard.js +2 -2
  3. package/components/Breadcrumbs.js +2 -2
  4. package/components/Checkbox.js +2 -2
  5. package/components/Chips.js +2 -2
  6. package/components/CopyButton.js +2 -2
  7. package/components/CtaButton.js +2 -2
  8. package/components/Drawer.js +3 -3
  9. package/components/Drawer.js.LICENSE.txt +3 -1
  10. package/components/EmbedContainer.js +2 -2
  11. package/components/Footer.js +2 -2
  12. package/components/FormAction.js +2 -2
  13. package/components/FormErrorSummary.js +2 -2
  14. package/components/FormGroup.js +2 -2
  15. package/components/FullWidth.js +2 -2
  16. package/components/Gallery.js +2 -2
  17. package/components/Hero.js +2 -2
  18. package/components/HighlightBox.js +2 -2
  19. package/components/HorizontalBookCard.js +3 -3
  20. package/components/HorizontalBookCard.js.LICENSE.txt +3 -1
  21. package/components/HorizontalCard.js +3 -3
  22. package/components/HorizontalCard.js.LICENSE.txt +3 -1
  23. package/components/IconCard.js +3 -3
  24. package/components/IconCard.js.LICENSE.txt +3 -1
  25. package/components/Legend.js +2 -2
  26. package/components/Loader.js +3 -3
  27. package/components/MegaMenu.js +2 -2
  28. package/components/Notice.js +2 -2
  29. package/components/PageHeader.js +2 -2
  30. package/components/Pager.js +2 -2
  31. package/components/ProgressBar.js +9 -0
  32. package/components/ProgressBar.js.LICENSE.txt +9 -0
  33. package/components/QuoteHighlight.js +3 -3
  34. package/components/QuoteHighlight.js.LICENSE.txt +3 -1
  35. package/components/Radio.js +2 -2
  36. package/components/Range.js +2 -2
  37. package/components/ScrollContainer.js +2 -2
  38. package/components/SegmentedControl.js +2 -2
  39. package/components/Select.js +2 -2
  40. package/components/ServiceNotice.js +2 -2
  41. package/components/ShareButtons.js +3 -3
  42. package/components/ShowMore.js +2 -2
  43. package/components/SkipLink.js +2 -2
  44. package/components/StatsCard.js +3 -3
  45. package/components/StatsCard.js.LICENSE.txt +3 -1
  46. package/components/SyndicationSearchWidget.js +3 -3
  47. package/components/Tab.js +2 -2
  48. package/components/TextCta.js +3 -3
  49. package/components/TextCta.js.LICENSE.txt +3 -1
  50. package/components/TextInput.js +2 -2
  51. package/components/Textarea.js +2 -2
  52. package/components/Tree.js +2 -2
  53. package/components/UserFeedback.js +2 -2
  54. package/components/VerticalCard.js +3 -3
  55. package/components/VerticalCard.js.LICENSE.txt +3 -1
  56. package/components/hydrate.js +2 -2
  57. package/css/style-all.css +110 -90
  58. package/css/style-all.css.map +1 -1
  59. package/css/style-delta.css +110 -90
  60. package/css/style-delta.css.map +1 -1
  61. package/css/style-gutenberg.css +9 -9
  62. package/css/style-irp.css +110 -90
  63. package/css/style-irp.css.map +1 -1
  64. package/css/style-mcr.css +110 -90
  65. package/css/style-mcr.css.map +1 -1
  66. package/css/style-preventionweb.css +110 -90
  67. package/css/style-preventionweb.css.map +1 -1
  68. package/css/style.css +110 -90
  69. package/css/style.css.map +1 -1
  70. package/docs/EDITORIAL-MANUAL.md +193 -0
  71. package/docs/llms-editorial-manual.txt +200 -0
  72. package/docs/llms-page-building.txt +1140 -0
  73. package/docs/llms-search-widget.txt +765 -0
  74. package/error-pages/401.html +1 -1
  75. package/error-pages/403.html +1 -1
  76. package/error-pages/404.html +1 -1
  77. package/error-pages/429.html +1 -1
  78. package/error-pages/500.html +1 -1
  79. package/error-pages/502.html +1 -1
  80. package/error-pages/503.html +1 -1
  81. package/error-pages/504.html +1 -1
  82. package/error-pages/5xx.html +1 -1
  83. package/error-pages/challenge.html +1 -1
  84. package/error-pages/managed-challenge.html +1 -1
  85. package/js/cite-this.js +352 -0
  86. package/package.json +6 -1
  87. package/scss/Atom/BaseTypography/Abbr/abbr.scss +1 -1
  88. package/scss/Atom/BaseTypography/Blockquote/blockquote.scss +1 -1
  89. package/scss/Atom/BaseTypography/Cite/cite.scss +1 -1
  90. package/scss/Atom/BaseTypography/Code/code.scss +1 -1
  91. package/scss/Atom/BaseTypography/Mark/mark.scss +1 -1
  92. package/scss/Atom/BaseTypography/Quotation/quotation.scss +1 -1
  93. package/scss/Atom/BaseTypography/Small/small.scss +1 -1
  94. package/scss/Atom/Colors/color.scss +1 -1
  95. package/scss/Atom/EmptyState/empty-state.scss +1 -1
  96. package/scss/Atom/Icons/_icon-definitions.scss +35 -3
  97. package/scss/Atom/Icons/icons.scss +1 -1
  98. package/scss/Atom/Images/AuthorImage/author-image.scss +1 -1
  99. package/scss/Atom/Images/Image/image.scss +1 -1
  100. package/scss/Atom/Images/ImageCaptionCredit/image-caption-credit.scss +7 -2
  101. package/scss/Atom/Images/ImageCredit/image-credit.scss +1 -1
  102. package/scss/Atom/Layout/Container/container.scss +1 -1
  103. package/scss/Atom/Layout/Grid/grid.scss +1 -1
  104. package/scss/Atom/Layout/Spacing/spacing.scss +1 -1
  105. package/scss/Atom/Logo/logo.scss +1 -1
  106. package/scss/Atom/Navigation/Breadcrumb/breadcrumb.scss +1 -1
  107. package/scss/Atom/Navigation/MenuItems/menu-items.scss +1 -1
  108. package/scss/Atom/ReachElement/Details/details.scss +1 -1
  109. package/scss/Atom/ReachElement/Figcaption/figcaption.scss +1 -1
  110. package/scss/Atom/StatusLabel/status-label.scss +1 -1
  111. package/scss/Atom/Table/table.scss +1 -1
  112. package/scss/Atom/Tag/tag.scss +1 -1
  113. package/scss/Atom/Video/video.scss +1 -1
  114. package/scss/Components/Boilerplate/boilerplate.scss +1 -1
  115. package/scss/Components/Breadcrumbs/breadcrumbs.scss +1 -1
  116. package/scss/Components/Buttons/Chips/chips.scss +1 -1
  117. package/scss/Components/Buttons/CopyButton/copy-button.scss +1 -1
  118. package/scss/Components/Buttons/CtaButton/buttons.scss +1 -1
  119. package/scss/Components/Buttons/CtaButton/cta-button.scss +1 -1
  120. package/scss/Components/Buttons/ShareButtons/share-buttons.scss +90 -1
  121. package/scss/Components/Cards/Card/card.scss +1 -1
  122. package/scss/Components/Cards/StatsCard/stats-card.scss +1 -1
  123. package/scss/Components/CiteThis/cite-this.scss +186 -0
  124. package/scss/Components/CookieConsentBanner/cookie-consent-banner.scss +1 -1
  125. package/scss/Components/DataViz/Legend/legend.scss +1 -1
  126. package/scss/Components/ErrorPages/error-pages.scss +1 -1
  127. package/scss/Components/Footer/footer.scss +1 -1
  128. package/scss/Components/Forms/Checkbox/checkbox.scss +1 -1
  129. package/scss/Components/Forms/FormAction/form-action.scss +1 -1
  130. package/scss/Components/Forms/FormGroup/form-group.scss +1 -1
  131. package/scss/Components/Forms/InputFields/input-fields.scss +1 -1
  132. package/scss/Components/Forms/Radio/radio.scss +1 -1
  133. package/scss/Components/Forms/Range/range.scss +1 -1
  134. package/scss/Components/Forms/SegmentedControl/segmented-control.scss +1 -1
  135. package/scss/Components/Forms/Select/select.scss +1 -1
  136. package/scss/Components/Forms/TextInput/text-input.scss +1 -1
  137. package/scss/Components/Forms/Textarea/textarea.scss +1 -1
  138. package/scss/Components/Forms/_form-base.scss +1 -1
  139. package/scss/Components/Gallery/gallery.scss +1 -1
  140. package/scss/Components/Hero/hero.scss +1 -1
  141. package/scss/Components/HighlightBox/highlight-box.scss +1 -1
  142. package/scss/Components/MegaMenu/mega-menu.scss +1 -1
  143. package/scss/Components/MegaMenu/megamenu.scss +1 -1
  144. package/scss/Components/Navigation/Drawer/drawer.scss +1 -1
  145. package/scss/Components/Navigation/Tree/tree.scss +1 -1
  146. package/scss/Components/Notice/notice.scss +1 -1
  147. package/scss/Components/OnThisPageNav/on-this-page-nav.scss +1 -1
  148. package/scss/Components/PageHeader/page-header.scss +1 -1
  149. package/scss/Components/Pager/pager.scss +1 -1
  150. package/scss/Components/PreviewAccess/preview-access.scss +1 -1
  151. package/scss/Components/ProgressBar/progress-bar.scss +215 -0
  152. package/scss/Components/QuoteHighlight/quote-highlight.scss +1 -1
  153. package/scss/Components/ScrollContainer/scroll-container.scss +1 -1
  154. package/scss/Components/Snackbar/snackbar.scss +1 -1
  155. package/scss/Components/SyndicationSearchWidget/_deprecated-teaser-hide.scss +1 -1
  156. package/scss/Components/SyndicationSearchWidget/syndication-search-widget.scss +1 -1
  157. package/scss/Components/Tab/tab.scss +1 -1
  158. package/scss/Components/TableOfContents/table-of-contents.scss +1 -1
  159. package/scss/Components/TextCta/text-cta.scss +1 -1
  160. package/scss/Components/TextCta/textcta.scss +1 -1
  161. package/scss/Components/UserFeedback/user-feedback.scss +1 -1
  162. package/scss/Molecules/ImageCaption/image-caption.scss +17 -3
  163. package/scss/Molecules/SectionHeader/section-header.scss +1 -1
  164. package/scss/Molecules/SectionHeader/sectionheader.scss +1 -1
  165. package/scss/Patterns/HubHeader/hub-header.scss +1 -1
  166. package/scss/Patterns/_shared/pattern-demo.scss +1 -1
  167. package/scss/Utilities/EmbedContainer/embed-container.scss +1 -1
  168. package/scss/Utilities/FullWidth/full-width.scss +1 -1
  169. package/scss/Utilities/Loader/loader.scss +55 -12
  170. package/scss/Utilities/Normalize/normalize.scss +1 -1
  171. package/scss/Utilities/PagePatterns/page-patterns.scss +1 -1
  172. package/scss/Utilities/ShowMore/show-more.scss +1 -1
  173. package/scss/Utilities/SkipLink/skip-link.scss +1 -1
  174. package/scss/assets/scss/_components.scss +2 -0
  175. package/scss/assets/scss/_variables.scss +2 -2
@@ -0,0 +1,1140 @@
1
+ # Mangrove page building guide for Drupal Gutenberg
2
+
3
+ > How to build landing pages on UNDRR websites (undrr.org, preventionweb.net, mcr2030.undrr.org and the microsites) with the Drupal Gutenberg block editor and Mangrove components: page shapes, section structure, layout patterns and component choice, then the UNDRR block reference with serialization rules, rendering constraints and the current markup for every block. Markup can be pasted into the editor through the Code editor. For copy, follow the editorial manual; for search widget configuration, fetch llms-search-widget.txt.
4
+
5
+ # Building landing pages
6
+
7
+ > **About this guidance:** this page brings together guidance maintained elsewhere and is provided for reference and ease of access. It is not the authoritative source. Where it differs from a source, or doesn't cover a point, follow the source: the block definitions in the Drupal `undrr_gutenberg_blocks` module as deployed (for block behaviour and markup), the [Editorial manual](https://mangrove.undrr.org/?path=/docs/contributing-editorial-manual--docs) and the sources it cites (for writing and style) and the [UNDRR Web Style Guide](https://unitednations.sharepoint.com/sites/UNDRR-DRR-COMMS/SitePages/Web-Style-Guide.aspx) (UNDRR staff only) (for UNDRR web style).
8
+
9
+ Guidance for editors building landing pages on UNDRR websites: which page shape to start from, how to structure sections and which Mangrove component suits each job. The structure and editorial advice comes first in each section; the Drupal Gutenberg markup that produces it follows.
10
+
11
+ ## Quick start for editors
12
+
13
+ > **First version:** a short outline for building a page in the visual editor, without writing code. A fuller editor guide will follow; the rest of this page has the detail.
14
+
15
+ 1. **Pick a page shape.** Decide what the page is for, then find its shape in [Choose a page shape](#choose-a-page-shape).
16
+ 2. **Insert a starting pattern.** Open the block inserter, switch to patterns and choose the **UNDRR pages** category. Insert the pattern closest to your page shape: a reading page, an initiative overview, a publication collection or a frequently asked questions section.
17
+ 3. **Replace the placeholders.** Rewrite every heading and paragraph, and check every link destination. Select each image, hero and card and choose a real image from the media library, with alt text and a photo credit. Follow the [Editorial manual](https://mangrove.undrr.org/llms-editorial-manual.txt) for the words.
18
+ 4. **Add a search widget if the page needs one.** Insert the **UNDRR Search Widget** block from the **UNDRR** category of the inserter and set it up in the block sidebar. [Search widget editor configuration](https://mangrove.undrr.org/llms-search-widget.txt) explains each setting and has ready-made recipes.
19
+ 5. **Preview.** Check the page before publishing, including at a narrow window width, and fix any block that shows a validation warning.
20
+ 6. **Publish** the page the way your website's editorial workflow requires.
21
+
22
+ Developers, and AI tools that write block markup, should start from [Drupal Gutenberg integration](#drupal-gutenberg-integration), which has the current markup for every block.
23
+
24
+ The [Landing page patterns](https://mangrove.undrr.org/?path=/docs/patterns-landing-pages--docs) page shows the three common page shapes rendered side by side. [Drupal Gutenberg integration](#drupal-gutenberg-integration) covers how each UNDRR block serializes and has the current markup for every block; this guide links to it rather than repeating it.
25
+
26
+ > **Tip:** An AI tool can read this guide and the integration guide as one plain-text file: <https://mangrove.undrr.org/llms-page-building.txt>. [Using this guide with an AI tool](#using-this-guide-with-an-ai-tool) has a prompt to start from.
27
+
28
+ ## Writing for landing pages
29
+
30
+ This guide covers structure, not prose. For the words on the page:
31
+
32
+ - [Editorial manual](https://mangrove.undrr.org/llms-editorial-manual.txt): capitalization, punctuation, numbers and dates, abbreviations, spelling, UNDRR terminology and inclusive language. It is the single source for these rules; the other guides link to it rather than restating it.
33
+ - [Writing guidelines](https://mangrove.undrr.org/?path=/docs/contributing-writing-guidelines--docs): plain language, front-loading and descriptive link text. Its rules on second person are written for interface copy; body copy on a landing page follows the editorial manual.
34
+ - UNDRR editorial guides for news, events, publications and blogs, being published at <https://assets.undrr.org/docs/editorial-guides/README.md>.
35
+
36
+ Points specific to landing pages:
37
+
38
+ - Write for the people who use UNDRR websites: Member States, disaster risk reduction practitioners, researchers and policymakers.
39
+ - Give every H2 section a short introduction of one or two sentences that says what the reader will find below. Keep it factual and action-oriented, and reference the Sendai Framework where it fits naturally.
40
+ - Use "disaster risk reduction" rather than "disaster management" or "disaster prevention", and spell it out before abbreviating it to DRR. Use "hazard" for the natural phenomenon and "disaster" for its impact on people.
41
+ - Headings are in sentence case.
42
+
43
+ ## Choose a page shape
44
+
45
+ Decide what the page is for before choosing blocks. Most UNDRR landing pages are one of these:
46
+
47
+ | The page… | Shape | Start from |
48
+ | --- | --- | --- |
49
+ | Introduces a subject and points several ways into it | Topic or initiative | A split hero, an on-this-page bar, then routes and recent material |
50
+ | Is one long document that people cite sections of | Report or publication | A coloured header with a contents sidebar, or a hero with an on-this-page bar; see [Publication landing page](#publication-landing-page) |
51
+ | Exists to reach many items | Collection index | A plain H1, a contents block and rows of book cards; see [Card grid rows](#card-grid-rows) |
52
+ | Presents several charts about one place or theme | Data page | See [Data chart page](#data-chart-page) |
53
+ | Is returned to repeatedly, with movement between sections | Content hub | See [Content hub](https://mangrove.undrr.org/?path=/docs/patterns-content-hub--docs) |
54
+
55
+ The inserter's **UNDRR pages** pattern category has starting points for a reading page, an initiative overview, a publication collection and a frequently asked questions section.
56
+
57
+ ## Page structure
58
+
59
+ ### Page title
60
+
61
+ Every page has exactly one H1. Either the hero supplies it (`headingLevel` `h1`) or a level 1 heading block does. Do not use the Drupal page title block (`drupalblock/page-title-block`) in the page body.
62
+
63
+ ```html
64
+ <!-- wp:heading {"level":1} -->
65
+ <h1 class="wp-block-heading">Page title</h1>
66
+ <!-- /wp:heading -->
67
+ ```
68
+
69
+ For a large display title on a publication or campaign page, set the font size to **Huge**, which saves `has-huge-font-size mg-u-font-size-800`.
70
+
71
+ ### Choosing a hero
72
+
73
+ The hero block has two layouts:
74
+
75
+ - **Split** (preferred for new pages): text in one column and an image, video or custom HTML in the other, on a solid theme colour. Contrast is predictable because the text never sits over a photograph.
76
+ - **Background** (legacy): text over a full-bleed image. Existing background heroes do not need migrating, but new pages should use split.
77
+
78
+ A newly inserted hero block starts on the background layout, so switch **Layout** to split in the block sidebar.
79
+
80
+ To draft a split hero before the image is in the media library, leave the image out: the hero saves no media column until an image is chosen, and the rest of the block still works. [Drupal Gutenberg integration: Hero](#hero) shows what to leave out of hand-written markup.
81
+
82
+ Split ratios describe the **content** column, which is the easiest thing to get backwards:
83
+
84
+ | Ratio | Content column | Use for |
85
+ | --- | --- | --- |
86
+ | 2/3 (default) | Two thirds | Text-led heroes: a long lede, several buttons, a supporting image |
87
+ | 1/2 | Half | Equal weight for a short lede and a strong image |
88
+ | 1/3 | One third | Video heroes, and any hero where the media is the message |
89
+
90
+ Use 1/3 for video: a video in a one-third column is too small to watch. Use custom HTML media for a statistic callout, a small chart or a captioned figure.
91
+
92
+ A hero has no slot for a contents list. Pair a hero with the [on-this-page bar](#in-page-navigation) directly below it, or use the [page header with a contents sidebar](#page-header-with-a-contents-sidebar) instead of a hero. A page with both reads as two headers.
93
+
94
+ Markup and attributes: [Drupal Gutenberg integration: Hero](#hero).
95
+
96
+ ### In-page navigation
97
+
98
+ Long pages need a way to jump between sections. There are two blocks for this, and a page uses one of them:
99
+
100
+ - **On this page navigation** (`undrr/undrr-on-this-page-nav-block`): a sticky horizontal bar built from the H2 headings. Use it on narrative and campaign pages, directly after the hero. To keep a download in view as the reader scrolls, turn on its call-to-action link.
101
+ - **Table of contents** (`undrr/undrr-table-of-contents-block`): a contents list, usually in a sidebar of the page header. Use it on index and reference pages.
102
+
103
+ Both read the page's headings, so the headings are the navigation: keep H2 text short and specific. To leave a heading out, add a class to it: `mg-on-this-page-nav--exclude` for the on-this-page bar, `mg-table-of-contents--exclude` for the contents list.
104
+
105
+ Markup: [Table of contents](#table-of-contents) and [On this page navigation](#on-this-page-navigation).
106
+
107
+ ### Page header with a contents sidebar
108
+
109
+ The reference-page alternative to a hero: a full-width coloured band with the title and lede on the left and the contents block on the right. The colour attributes go on the outer columns block, and the contents block sits directly in the right column.
110
+
111
+ ```html
112
+ <!-- wp:columns {"backgroundColor":"undrr-blue","textColor":"white","style":{"elements":{"link":{"color":{"text":"var:preset|color|white"}}}},"undrrUtilityClasses":["mg-container-full-width"]} -->
113
+ <div class="wp-block-columns has-white-color has-undrr-blue-background-color has-text-color has-background has-link-color mg-container-full-width"><!-- wp:column {"width":"66.66%"} -->
114
+ <div class="wp-block-column" style="flex-basis:66.66%"><!-- wp:heading {"level":1,"fontSize":"huge"} -->
115
+ <h1 class="wp-block-heading has-huge-font-size mg-u-font-size-800">Page title</h1>
116
+ <!-- /wp:heading -->
117
+
118
+ [lede paragraphs and a left-aligned outline download button]
119
+
120
+ </div>
121
+ <!-- /wp:column -->
122
+
123
+ <!-- wp:column {"verticalAlignment":"center","width":"33.33%"} -->
124
+ <div class="wp-block-column is-vertically-aligned-center" style="flex-basis:33.33%">[table of contents block]</div>
125
+ <!-- /wp:column --></div>
126
+ <!-- /wp:columns -->
127
+ ```
128
+
129
+ When the introduction runs on after the header, continue it in a plain 66.66/33.33 columns block so the text stays aligned under the header.
130
+
131
+ ### Section introductions
132
+
133
+ Each H2 section opens with its heading and a one- or two-sentence introduction, then its content. On campaign and long narrative pages, section H2s can be set to the **Huge** font size for a stronger break between sections; keep default sizing on index and reference pages.
134
+
135
+ ### Section backgrounds
136
+
137
+ A full-width tinted band marks a change of job, such as a hand-off or a call to action at the end of a narrative run. On index pages, alternating white and light grey sections give a long page some rhythm. Used on every ordinary section, tinted bands just stripe the page.
138
+
139
+ Wrap the section in a columns block with one column. Do not use a group block as the wrapper; it breaks in Drupal Gutenberg.
140
+
141
+ ```html
142
+ <!-- wp:columns {"backgroundColor":"undrr-light-grey","undrrUtilityClasses":["mg-container-full-width"]} -->
143
+ <div class="wp-block-columns has-undrr-light-grey-background-color has-background mg-container-full-width"><!-- wp:column -->
144
+ <div class="wp-block-column">
145
+
146
+ [H2, introduction and the section content]
147
+
148
+ </div>
149
+ <!-- /wp:column --></div>
150
+ <!-- /wp:columns -->
151
+ ```
152
+
153
+ To hold the section content to the default content width inside the band, put a constrained group inside the column. This is the one place a group block works:
154
+
155
+ ```html
156
+ <!-- wp:columns {"backgroundColor":"undrr-light-grey","undrrUtilityClasses":["mg-container-full-width"]} -->
157
+ <div class="wp-block-columns has-undrr-light-grey-background-color has-background mg-container-full-width"><!-- wp:column {"width":"100%"} -->
158
+ <div class="wp-block-column" style="flex-basis:100%"><!-- wp:group {"layout":{"type":"constrained"}} -->
159
+ <div class="wp-block-group">
160
+
161
+ [H2, introduction and the section content]
162
+
163
+ </div>
164
+ <!-- /wp:group --></div>
165
+ <!-- /wp:column --></div>
166
+ <!-- /wp:columns -->
167
+ ```
168
+
169
+ For a band that also needs a centred reading column, put the percentage columns (below) directly in the band's columns block rather than nesting a second one.
170
+
171
+ Background colours belong on a container, not on a column in a row. A coloured column has no padding, so the text runs to its edges. For a call-out beside body text, put a [Highlight box](#highlight-box) in a plain column instead.
172
+
173
+ ### Reading column widths
174
+
175
+ Long lines are hard to read. On narrative pages (annual reports, flagship publications, concept notes), centre body text in a narrower column and let full-width elements such as the hero, the on-this-page bar and stats cards break out of it. The side columns collapse on mobile.
176
+
177
+ | Split | Use for |
178
+ | --- | --- |
179
+ | 15/70/15 | Wide featured text, a hero-style lede, full-width call-to-action bars and download buttons |
180
+ | 20/60/20 | Body prose: roughly four or more consecutive paragraphs, and show-more targets |
181
+
182
+ ```html
183
+ <!-- wp:columns -->
184
+ <div class="wp-block-columns"><!-- wp:column {"width":"20%"} -->
185
+ <div class="wp-block-column" style="flex-basis:20%"></div>
186
+ <!-- /wp:column -->
187
+
188
+ <!-- wp:column {"width":"60%"} -->
189
+ <div class="wp-block-column" style="flex-basis:60%">
190
+
191
+ [paragraphs]
192
+
193
+ </div>
194
+ <!-- /wp:column -->
195
+
196
+ <!-- wp:column {"width":"20%"} -->
197
+ <div class="wp-block-column" style="flex-basis:20%"></div>
198
+ <!-- /wp:column --></div>
199
+ <!-- /wp:columns -->
200
+ ```
201
+
202
+ Do not use reading columns on index and reference pages, where full-width card rows use the space better.
203
+
204
+ ### Spacing
205
+
206
+ Headings carry the rhythm, not spacers. A spacer between every H2 is usually the wrong tool; default block spacing plus clear section headings reads better, with a spacer kept for a genuine break. Where spacers are used, these values keep pages consistent:
207
+
208
+ | Where | Spacer |
209
+ | --- | --- |
210
+ | Between H2 sections on index and reference pages | 60px |
211
+ | Between H2 sections on campaign and narrative pages | 45px |
212
+ | Above the contents block, and below it | 32px, 40px |
213
+ | Between chart rows in a data page section | 40px |
214
+ | Top and bottom inside a tinted band | 48px |
215
+ | Between two tightly coupled blocks | 8px |
216
+
217
+ Card rows within a section need no spacer; default block spacing handles them.
218
+
219
+ ### Composition defaults
220
+
221
+ Observations from pages that have been through editorial review, offered as defaults rather than rules:
222
+
223
+ - **Fill the short column or do not split.** A 66.66/33.33 split with an empty right column looks like a mistake once it repeats down a page. Put the pull quote, supporting image or diagram there.
224
+ - **Stats cards want full width.** In a one-third column their figures stack into a narrow strip. Place them between sections, not inside a split.
225
+ - **Buttons align left**, on the same axis as the text they follow. Centred buttons float free of the reading column.
226
+ - **A large first paragraph works as a lede.** The **Large** font size on a section's opening paragraph gives readers a way in without another heading level.
227
+
228
+ ## Page archetypes
229
+
230
+ ### Card grid rows
231
+
232
+ For collection index pages, which exist to reach many items:
233
+
234
+ - Put a full-width H3 above each row of cards, not inside a column.
235
+ - Below the H3, add a paragraph linking to the subsection's own landing page. Name the destination in the link text ("All early warning resources"), not a generic "View landing page", which reads the same for every row to a screen reader user scanning links. When the subsection covers two related topics, add both links separated by a line break.
236
+ - Lay book cards out in five-column rows, and pad a short row with empty columns so the covers keep their size.
237
+ - When two neighbouring subsections have only one or two cards each, merge them under one H3.
238
+ - Turn items that do not suit a card (training modules, other landing pages) into text links.
239
+ - Put editorial labels such as "(Suggested)" in the title text rather than the card's label.
240
+
241
+ ```html
242
+ <!-- wp:heading {"level":3} -->
243
+ <h3 class="wp-block-heading">Subsection name</h3>
244
+ <!-- /wp:heading -->
245
+
246
+ <!-- wp:paragraph -->
247
+ <p><a href="https://www.undrr.org/example">All early warning resources</a></p>
248
+ <!-- /wp:paragraph -->
249
+
250
+ <!-- wp:columns -->
251
+ <div class="wp-block-columns"><!-- wp:column -->
252
+ <div class="wp-block-column">[book card]</div>
253
+ <!-- /wp:column -->
254
+
255
+ <!-- wp:column -->
256
+ <div class="wp-block-column">[book card]</div>
257
+ <!-- /wp:column -->
258
+
259
+ <!-- wp:column -->
260
+ <div class="wp-block-column">[book card]</div>
261
+ <!-- /wp:column -->
262
+
263
+ <!-- wp:column -->
264
+ <div class="wp-block-column"></div>
265
+ <!-- /wp:column -->
266
+
267
+ <!-- wp:column -->
268
+ <div class="wp-block-column"></div>
269
+ <!-- /wp:column --></div>
270
+ <!-- /wp:columns -->
271
+ ```
272
+
273
+ Book card markup is in [Drupal Gutenberg integration: Card](#card).
274
+
275
+ ### Publication landing page
276
+
277
+ For annual reports and other PDF-led publications, the web page is a guided tour that sends readers to the full document, not a copy of it:
278
+
279
+ 1. A hero with the cover image or a video.
280
+ 2. An on-this-page bar with a download call to action.
281
+ 3. The foreword or introduction in a 15/70/15 reading column.
282
+ 4. Key figures in full-width stats cards.
283
+ 5. Thematic H2 sections, each with a story preview cut to two or three paragraphs and a "Read more in the full report (PDF)" link.
284
+ 6. Quote highlights for official quotes from named people.
285
+ 7. Cross-cutting themes as vertical cards linking to the thematic pages, rather than repeating text that is already in the PDF.
286
+ 8. A download section with book cards for the PDF and any annexes.
287
+ 9. A "More on UNDRR" section with vertical cards linking to related pages.
288
+
289
+ Alternate white and grey section backgrounds down the page. Global Assessment Report 2025 and the UNDRR Annual Reports 2024 and 2025 follow this shape.
290
+
291
+ ```html
292
+ <!-- wp:paragraph -->
293
+ <p>The first two or three paragraphs of the story from the report.</p>
294
+ <!-- /wp:paragraph -->
295
+
296
+ <!-- wp:paragraph -->
297
+ <p><a href="/media/[media ID]/download">Read more in the full report (PDF)</a></p>
298
+ <!-- /wp:paragraph -->
299
+ ```
300
+
301
+ ### Data chart page
302
+
303
+ For pages built around several charts, such as country resilience profiles or thematic dashboards, with three to five thematic sections. Keep prose brief: one framing sentence per section and one key finding per chart.
304
+
305
+ 1. A full-width blue header: a back link, the H1, a row of metadata in four columns, a separator and a one- or two-sentence lead paragraph, in white text.
306
+ 2. An on-this-page bar built from the H2s.
307
+ 3. Thematic sections, alternating white and grey. Each opens with a short section label, an H2 with an anchor and a framing paragraph, followed by one row per chart.
308
+
309
+ Each chart row is a columns block split 33.33/66.66: an H3 stating the key message, one or two sentences of supporting data and an outline button on the left; the chart and its caption on the right.
310
+
311
+ ```html
312
+ <!-- wp:columns -->
313
+ <div class="wp-block-columns"><!-- wp:column {"verticalAlignment":"top","width":"33.33%"} -->
314
+ <div class="wp-block-column is-vertically-aligned-top" style="flex-basis:33.33%"><!-- wp:heading {"level":3} -->
315
+ <h3 class="wp-block-heading">[Key finding, stated as a message]</h3>
316
+ <!-- /wp:heading -->
317
+
318
+ <!-- wp:paragraph -->
319
+ <p>One or two sentences supporting the key message with specific data.</p>
320
+ <!-- /wp:paragraph --></div>
321
+ <!-- /wp:column -->
322
+
323
+ <!-- wp:column {"verticalAlignment":"top","width":"66.66%"} -->
324
+ <div class="wp-block-column is-vertically-aligned-top" style="flex-basis:66.66%"><!-- wp:html -->
325
+ <iframe title="[Key finding, stated as a message]" src="https://datawrapper.dwcdn.net/XXXXX/1/" scrolling="no" frameborder="0" style="width: 0; min-width: 100% !important; border: none;" height="425" data-external="1"></iframe>
326
+ <!-- /wp:html -->
327
+
328
+ <!-- wp:paragraph {"fontSize":"small"} -->
329
+ <p class="has-small-font-size mg-u-font-size-250">[Metric, units and scope]. <em>Source</em>: [organization] ([year])</p>
330
+ <!-- /wp:paragraph --></div>
331
+ <!-- /wp:column --></div>
332
+ <!-- /wp:columns -->
333
+ ```
334
+
335
+ Chart titles and captions follow a convention. The text in square brackets is a placeholder: write the finding and source from the data the chart shows.
336
+
337
+ | Element | Content | Form |
338
+ | --- | --- | --- |
339
+ | H3 in the left column | The key takeaway, stated as a message | "[What the data shows, in one sentence]" |
340
+ | `iframe` `title` | The same text as the H3; it is the chart's accessible name | The H3 text |
341
+ | Caption paragraph | Neutral: metric, units, scope and source, with the source line following the [editorial manual's template](https://mangrove.undrr.org/llms-editorial-manual.txt#undrr-specific-terminology) | "[Metric] ([units]), [scope]. _Source_: [organization] ([year])" |
342
+ | Title inside the chart | Can be hidden in the chart tool's publish settings | |
343
+
344
+ Datawrapper's own embed code adds a script that resizes the iframe; include it in the same `wp:html` block.
345
+
346
+ ### Logo wall
347
+
348
+ For partner and consortium logos, use icon cards with `imageScale` `full` and `centered` on, six to a row, inside a 10/80/10 centring wrapper.
349
+
350
+ - For an organization with no usable logo, use a text-only icon card.
351
+ - For a logo that only exists in white, give that one column `"backgroundColor":"undrr-blue","textColor":"white"`.
352
+ - A first version can hotlink logos from the organizations' own websites by setting the image URL and leaving out `mediaID`; upload them to the media library before the page is final.
353
+
354
+ Icon card markup is in [Drupal Gutenberg integration: Card](#card).
355
+
356
+ ## Choosing components
357
+
358
+ ### Cards
359
+
360
+ | Content | Card |
361
+ | --- | --- |
362
+ | Topics, programmes or pages, each with a picture and a short description | Vertical card (`vc`) |
363
+ | The same, where a row of vertical cards would be too tall | Horizontal card (`hc`) |
364
+ | Publications and documents with a cover | Book card (`book`), or horizontal book card (`hc_book`) in a list |
365
+ | Partner logos and short route links | Icon card (`icon`) |
366
+
367
+ - Always give vertical and horizontal cards an image. Without one they lose their border, background and padding and render as bare text.
368
+ - Keep summaries to two or three sentences. Long summaries make rows ragged, because each card grows to its own content.
369
+ - Cover images are decorative when the title is beside them: set `mediaAlt` to an empty string. Photographs in content cards need descriptive alt text.
370
+ - Publication cover scans (the generated document thumbnails in the media library) look wrong in a vertical card; use a photograph.
371
+
372
+ ### Figures and statistics
373
+
374
+ Use the [stats card](#stats-card) for headline figures, at full width. When there are more figures than fit one row, put several single-stat cards, each without a title, inside a [scroll container](#scroll-container) rather than stacking rows. Write figures the way the [editorial manual](https://mangrove.undrr.org/llms-editorial-manual.txt#numbers-and-dates) sets out.
375
+
376
+ ### Quotes
377
+
378
+ Use the [Quote highlight](#quote-highlight) block for a quote with a named speaker, their title and optionally a portrait. For a pull quote with no attribution beside body text, a blockquote in the right-hand column of a 60/40 split is lighter:
379
+
380
+ ```html
381
+ <!-- wp:columns {"backgroundColor":"undrr-light-grey","undrrUtilityClasses":["mg-container-full-width"]} -->
382
+ <div class="wp-block-columns has-undrr-light-grey-background-color has-background mg-container-full-width"><!-- wp:column {"width":"60%"} -->
383
+ <div class="wp-block-column" style="flex-basis:60%">
384
+
385
+ [H2 and body paragraphs]
386
+
387
+ </div>
388
+ <!-- /wp:column -->
389
+
390
+ <!-- wp:column {"verticalAlignment":"center","width":"40%"} -->
391
+ <div class="wp-block-column is-vertically-aligned-center" style="flex-basis:40%"><!-- wp:html -->
392
+ <blockquote class="mg-quote-highlight mg-u-font-size-600">Pull quote text.</blockquote>
393
+ <!-- /wp:html --></div>
394
+ <!-- /wp:column --></div>
395
+ <!-- /wp:columns -->
396
+ ```
397
+
398
+ ### Show more
399
+
400
+ The show more button collapses a long block, such as a list of resources, behind a toggle. It needs two things: a unique class on the block to collapse, and a layout that centres the button.
401
+
402
+ 1. Give the content's columns block a class such as `show-more-target-k7q2xa`, with a random six- to eight-character suffix so that two show more blocks on one page cannot collide.
403
+ 2. Put the button in its own columns row directly below, in the middle column of a 40/20/40 split.
404
+ 3. Add a page-level style to centre the button.
405
+
406
+ ```html
407
+ <!-- wp:columns {"className":"show-more-target-k7q2xa"} -->
408
+ <div class="wp-block-columns show-more-target-k7q2xa"><!-- wp:column {"width":"20%"} -->
409
+ <div class="wp-block-column" style="flex-basis:20%"></div>
410
+ <!-- /wp:column -->
411
+
412
+ <!-- wp:column {"width":"60%"} -->
413
+ <div class="wp-block-column" style="flex-basis:60%">
414
+
415
+ [content to collapse]
416
+
417
+ </div>
418
+ <!-- /wp:column -->
419
+
420
+ <!-- wp:column {"width":"20%"} -->
421
+ <div class="wp-block-column" style="flex-basis:20%"></div>
422
+ <!-- /wp:column --></div>
423
+ <!-- /wp:columns -->
424
+
425
+ <!-- wp:columns -->
426
+ <div class="wp-block-columns"><!-- wp:column {"width":"40%"} -->
427
+ <div class="wp-block-column" style="flex-basis:40%"></div>
428
+ <!-- /wp:column -->
429
+
430
+ <!-- wp:column {"verticalAlignment":"center","width":"20%"} -->
431
+ <div class="wp-block-column is-vertically-aligned-center" style="flex-basis:20%"><!-- wp:undrr/undrr-show-more-button {"targetSelector":".show-more-target-k7q2xa","collapsedHeight":300} -->
432
+ <div class="wp-block-undrr-undrr-show-more-button"><style>.show-more-target-k7q2xa{--mg-show-more-height:300px}</style><a href="#" class="mg-button mg-button-primary mg-show-more--button" data-mg-show-more="true" data-mg-show-more-target=".show-more-target-k7q2xa" data-mg-show-more-label-collapsed="Show more" data-mg-show-more-label-open="Show less">Show more</a></div>
433
+ <!-- /wp:undrr/undrr-show-more-button --></div>
434
+ <!-- /wp:column -->
435
+
436
+ <!-- wp:column {"width":"40%"} -->
437
+ <div class="wp-block-column" style="flex-basis:40%"></div>
438
+ <!-- /wp:column --></div>
439
+ <!-- /wp:columns -->
440
+
441
+ <!-- wp:html -->
442
+ <style>
443
+ .wp-block-undrr-undrr-show-more-button {
444
+ text-align: center;
445
+ }
446
+ </style>
447
+ <!-- /wp:html -->
448
+ ```
449
+
450
+ ### Frequently asked questions and long reference content
451
+
452
+ There are two tools for content that readers expand one item at a time:
453
+
454
+ - **A short set of questions** (up to about ten): use the **Frequently asked questions** pattern from the **UNDRR pages** category. It inserts core Details blocks with the Mangrove presentation switched on, one per question. Details are native HTML disclosures, so they need no script and the browser's find-in-page search reaches the answers.
455
+ - **Long reference content**, such as a long question list or the Sendai Framework targets and indicators: use stacked tabs with **Show filter input** and **Single open (accordion)** turned on, so readers can type a word and go straight to the matching section. Horizontal tabs are the wrong tool here; they truncate their labels and make readers click through each tab. Write section labels with the words a reader would search for.
456
+
457
+ When a stacked tab set sits inside an H2 section and the tab labels are the only headings needed, turn on **Hide heading** for each section. Otherwise each open panel repeats its label as a visible H2 below the tab, which duplicates the heading.
458
+
459
+ Markup: [Drupal Gutenberg integration: Tabs](#tabs).
460
+
461
+ ### Images and video
462
+
463
+ - Use images from the media library, with alt text that describes what the image shows. Every photograph needs a credit.
464
+ - Put images inside a reading column rather than full width, unless the image is the point of the section.
465
+ - For video, use the embed block with the ordinary YouTube or Vimeo URL, and put the caption in a small paragraph after it. Hero video is different: it needs the `/embed/` URL.
466
+
467
+ Markup: [Drupal Gutenberg integration: Core blocks](#core-blocks-used-alongside-the-undrr-blocks).
468
+
469
+ ## Starter page
470
+
471
+ A minimal index page: title, contents, one white section of book cards and one grey section. Paste it through the Code editor, then replace the placeholder text, links and images; `[cover image URL]` stands for the URL of an image chosen from the media library. Elsewhere in this guide, text in square brackets is a placeholder. On a line of its own, such as `[book card]`, it marks where other blocks go and is not valid block markup, so replace it with real blocks before pasting. Inside a block, such as `[Key finding, stated as a message]`, it is a value to replace with real content.
472
+
473
+ ```html
474
+ <!-- wp:heading {"level":1} -->
475
+ <h1 class="wp-block-heading">Landing page title</h1>
476
+ <!-- /wp:heading -->
477
+
478
+ <!-- wp:spacer {"height":"32px"} -->
479
+ <div style="height:32px" aria-hidden="true" class="wp-block-spacer"></div>
480
+ <!-- /wp:spacer -->
481
+
482
+ <!-- wp:undrr/undrr-table-of-contents-block -->
483
+ <section class="wp-block-undrr-undrr-table-of-contents-block mg-table-of-contents" data-mg-table-of-contents="true" data-mg-table-of-contents-title="On this page" data-mg-table-of-contents-show-title="true" data-mg-table-of-contents-skip-auto-init="true"></section>
484
+ <!-- /wp:undrr/undrr-table-of-contents-block -->
485
+
486
+ <!-- wp:spacer {"height":"40px"} -->
487
+ <div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>
488
+ <!-- /wp:spacer -->
489
+
490
+ <!-- wp:heading -->
491
+ <h2 class="wp-block-heading">First section</h2>
492
+ <!-- /wp:heading -->
493
+
494
+ <!-- wp:paragraph -->
495
+ <p>One or two sentences on what readers will find in this section.</p>
496
+ <!-- /wp:paragraph -->
497
+
498
+ <!-- wp:columns -->
499
+ <div class="wp-block-columns"><!-- wp:column -->
500
+ <div class="wp-block-column"><!-- wp:undrr/undrr-card {"title":"Resource A","titleLink":"https://www.undrr.org/example-a","cardType":"book","mediaAlt":""} -->
501
+ <article class="wp-block-undrr-undrr-card mg-card mg-card__book"><div class="mg-card__visual"><img src="[cover image URL]" alt="" class="mg-card__image" loading="lazy"/></div><div class="mg-card__content"><header class="mg-card__title"><a href="https://www.undrr.org/example-a">Resource A</a></header></div></article>
502
+ <!-- /wp:undrr/undrr-card --></div>
503
+ <!-- /wp:column -->
504
+
505
+ <!-- wp:column -->
506
+ <div class="wp-block-column"><!-- wp:undrr/undrr-card {"title":"Resource B","titleLink":"https://www.undrr.org/example-b","cardType":"book","mediaAlt":""} -->
507
+ <article class="wp-block-undrr-undrr-card mg-card mg-card__book"><div class="mg-card__visual"><img src="[cover image URL]" alt="" class="mg-card__image" loading="lazy"/></div><div class="mg-card__content"><header class="mg-card__title"><a href="https://www.undrr.org/example-b">Resource B</a></header></div></article>
508
+ <!-- /wp:undrr/undrr-card --></div>
509
+ <!-- /wp:column -->
510
+
511
+ <!-- wp:column -->
512
+ <div class="wp-block-column"></div>
513
+ <!-- /wp:column -->
514
+
515
+ <!-- wp:column -->
516
+ <div class="wp-block-column"></div>
517
+ <!-- /wp:column -->
518
+
519
+ <!-- wp:column -->
520
+ <div class="wp-block-column"></div>
521
+ <!-- /wp:column --></div>
522
+ <!-- /wp:columns -->
523
+
524
+ <!-- wp:spacer {"height":"60px"} -->
525
+ <div style="height:60px" aria-hidden="true" class="wp-block-spacer"></div>
526
+ <!-- /wp:spacer -->
527
+
528
+ <!-- wp:columns {"backgroundColor":"undrr-light-grey","undrrUtilityClasses":["mg-container-full-width"]} -->
529
+ <div class="wp-block-columns has-undrr-light-grey-background-color has-background mg-container-full-width"><!-- wp:column -->
530
+ <div class="wp-block-column"><!-- wp:heading -->
531
+ <h2 class="wp-block-heading">Second section</h2>
532
+ <!-- /wp:heading -->
533
+
534
+ <!-- wp:paragraph -->
535
+ <p>One or two sentences on what readers will find in this section.</p>
536
+ <!-- /wp:paragraph -->
537
+
538
+ <!-- wp:paragraph -->
539
+ <p>Replace this paragraph with a row of cards, as in the first section.</p>
540
+ <!-- /wp:paragraph --></div>
541
+ <!-- /wp:column --></div>
542
+ <!-- /wp:columns -->
543
+ ```
544
+
545
+ ## Found a problem?
546
+
547
+ If something in this guide is wrong or out of date, open an issue in the [Mangrove issue queue](https://github.com/PreventionWeb/undrr-mangrove/issues) (a GitHub account is needed).
548
+
549
+ ## Related documentation
550
+
551
+ - [Drupal Gutenberg integration](#drupal-gutenberg-integration): block reference, serialization rules and rendering constraints
552
+ - [Search widget editor configuration](https://mangrove.undrr.org/llms-search-widget.txt): adding a search or "latest content" panel to a page
553
+ - [Landing page patterns](https://mangrove.undrr.org/?path=/docs/patterns-landing-pages--docs) and [Content hub](https://mangrove.undrr.org/?path=/docs/patterns-content-hub--docs): rendered examples of these shapes
554
+ - [Component gallery](https://mangrove.undrr.org/?path=/docs/brand-component-gallery--docs): every component, grouped by what it is for
555
+
556
+ # Drupal Gutenberg integration
557
+
558
+ > **About this guidance:** this page brings together guidance maintained elsewhere and is provided for reference and ease of access. It is not the authoritative source. Where it differs from a source, or doesn't cover a point, follow the source: the block definitions and `save()` output in the Drupal `undrr_gutenberg_blocks` module as deployed (for blocks, attributes and markup), the [Editorial manual](https://mangrove.undrr.org/?path=/docs/contributing-editorial-manual--docs) and the sources it cites (for writing and style) and the [UNDRR Web Style Guide](https://unitednations.sharepoint.com/sites/UNDRR-DRR-COMMS/SitePages/Web-Style-Guide.aspx) (UNDRR staff only) (for UNDRR web style).
559
+
560
+ UNDRR websites (undrr.org, preventionweb.net, mcr2030.undrr.org and the microsites) run on a shared Drupal platform, and editors build landing pages there with the Gutenberg block editor. Most of what an editor places on a page is a Mangrove component wrapped in a Gutenberg block. This page is the thin layer between the two: which block renders which component, how the blocks serialize, what the deployed build can and cannot render, and the current markup for each block.
561
+
562
+ It has two companions:
563
+
564
+ - [Building landing pages](#building-landing-pages): the editorial and structural guidance, meaning which page shapes to use and how to compose them. Start there if you are planning a page.
565
+ - [Search widget editor configuration](https://mangrove.undrr.org/llms-search-widget.txt): filters, facets and search syntax for the UNDRR search widget block.
566
+
567
+ ## Using this guide with an AI tool
568
+
569
+ The Storybook site is a single-page app, so an AI tool that fetches a Storybook URL gets an empty shell. Every build publishes this guide and [Building landing pages](#building-landing-pages) as one plain-text file instead: <https://mangrove.undrr.org/llms-page-building.txt>. The search widget reference has its own file: <https://mangrove.undrr.org/llms-search-widget.txt>.
570
+
571
+ Use this prompt in any AI tool that can fetch URLs:
572
+
573
+ > Using the UNDRR page building guide at https://mangrove.undrr.org/llms-page-building.txt, draft a Drupal Gutenberg landing page about disaster preparedness with a split hero, an on-this-page navigation bar and three sections of book cards.
574
+
575
+ Replace everything after "draft" with your page brief. Add <https://mangrove.undrr.org/llms-editorial-manual.txt> to the prompt when the tool is also writing the copy, and <https://mangrove.undrr.org/llms-search-widget.txt> when the page needs a search widget.
576
+
577
+ If you use Claude Code or Cursor with access to the block module source, the [drupal-gutenberg-llm-skills](https://github.com/khawkins98/drupal-gutenberg-llm-skills) plugin gives better results because it validates against the full block definitions.
578
+
579
+ Review AI output in the editor before publishing. A block the editor cannot validate shows an "Attempt block recovery" prompt; recovering it rewrites the markup to what the block would save, which usually drops attributes. The search widget is an exception: all its settings are in the block comment, so recovery rebuilds its markup from them and loses nothing.
580
+
581
+ ## Platform context
582
+
583
+ The platform uses the [Drupal Gutenberg module](https://www.drupal.org/project/gutenberg), a port of the WordPress block editor to Drupal. Block comments keep the WordPress `wp:` prefix, but a few things differ from WordPress:
584
+
585
+ - Landing pages use the `landing_page_gutenberg` content type.
586
+ - Blocks are registered in JavaScript and `*.gutenberg.yml`; there is no `block.json`.
587
+ - Libraries load through Drupal's `*.libraries.yml`, not `wp_enqueue_script()`.
588
+ - Translations use `Drupal.t()`, wrapped as `__()` in block code.
589
+ - `wp:group` does not work as a standalone section wrapper. Use `wp:columns` with a single `wp:column` child instead (see [Serialization rules](#serialization-rules)).
590
+
591
+ The UNDRR blocks live in the `undrr_gutenberg_blocks` Drupal module, in the platform codebase. Each block's `save()` function writes Mangrove markup (the `mg-` classes and `data-mg-*` attributes documented on each component page), and the Mangrove CSS and scripts that the theme loads style and hydrate it on the published page.
592
+
593
+ ## Pasting markup into the editor
594
+
595
+ 1. Open the page in the block editor.
596
+ 2. Open the three-dot menu at the top right and choose **Code editor**.
597
+ 3. Paste the markup where it belongs, then choose **Exit code editor**.
598
+ 4. Check every block in the visual editor. A block with a validation warning has markup that does not match what the block saves; fix the markup or rebuild that block in the visual editor.
599
+
600
+ The body field's text format must be **Gutenberg**. It is the only format that parses block comments, renders dynamic blocks and resolves embeds. Markup saved under any other format, Full HTML included, is stored without complaint and then rendered as plain HTML: embeds print their URL as text, dynamic blocks such as the media entity block render nothing, and every block comment appears in the page source. Static blocks still look right, so a page can seem mostly fine while every dynamic block is broken. `<!-- wp:` in the page source is the give-away. Saving the page once through the editor sets the format.
601
+
602
+ ## Where the markup comes from
603
+
604
+ The source of truth for every UNDRR block's serialized markup is that block's `save()` output in the `undrr_gutenberg_blocks` module. The examples on this page reproduce it so that editors and AI tools can work without access to the platform codebase. The module's maintainers keep the two in step: when a block's `save()` output changes, the matching example here is updated in the same round of work.
605
+
606
+ When an example here and the editor disagree, the editor wins. Build the block in the visual editor, open the Code editor and copy what it saved.
607
+
608
+ Media IDs, file paths, image style tokens (`?h=…&itok=…`), file UUIDs and `/media/…` links in the examples are illustrative. They belong to items in one website's media library, so on another website they point at nothing or at something else. Replace them with values from the media library of the website you are editing, or leave the media out while drafting, as described for each block.
609
+
610
+ Blocks keep older save formats as deprecations, so pages saved with earlier markup (nested card wrappers, the previous stats card format, heroes without `mg-hero--no-image`) still validate and are rewritten to the current format the next time the block is saved.
611
+
612
+ ## UNDRR blocks and the Mangrove components they render
613
+
614
+ All UNDRR blocks sit in the **UNDRR** category of the block inserter.
615
+
616
+ | Block (inserter name) | Registration name | Renders | Notes |
617
+ | --- | --- | --- | --- |
618
+ | UNDRR Hero | `undrr/undrr-hero-block` | [Hero](https://mangrove.undrr.org/?path=/docs/components-hero-hero--docs) | Split layout preferred; see [Hero](#hero) |
619
+ | UNDRR Card | `undrr/undrr-card` | [Vertical card](https://mangrove.undrr.org/?path=/docs/components-cards-vertical-card--docs), [Horizontal card](https://mangrove.undrr.org/?path=/docs/components-cards-horizontal-card--docs), [Book card](https://mangrove.undrr.org/?path=/docs/components-cards-book-card--docs), [Horizontal book card](https://mangrove.undrr.org/?path=/docs/components-cards-horizontal-book-card--docs), [Icon card](https://mangrove.undrr.org/?path=/docs/components-cards-icon-card--docs) | One block, five card types via `cardType` |
620
+ | Stats card | `undrr/stats-card` | [Stats card](https://mangrove.undrr.org/?path=/docs/components-cards-stats-card--docs) | Hydrated from `data-stats` |
621
+ | Tabs V2 and Tab section V2 | `undrr/undrr-tabs-v2-block`, `undrr/undrr-tabs-v2-section` | [Tabs](https://mangrove.undrr.org/?path=/docs/components-tabs--docs) | Horizontal or stacked |
622
+ | Table of contents | `undrr/undrr-table-of-contents-block` | [Table of contents](https://mangrove.undrr.org/?path=/docs/components-navigation-table-of-contents--docs) | Sidebar contents list |
623
+ | On this page navigation | `undrr/undrr-on-this-page-nav-block` | [On this page nav](https://mangrove.undrr.org/?path=/docs/components-navigation-on-this-page-nav--docs) | Sticky bar built from headings |
624
+ | Show more button | `undrr/undrr-show-more-button` | [Show more](https://mangrove.undrr.org/?path=/docs/components-showmore--docs) | Collapses another block |
625
+ | Scroll container | `undrr/undrr-scroll-container` | [Scroll container](https://mangrove.undrr.org/?path=/docs/components-scrollcontainer--docs) | Horizontal scrolling row |
626
+ | Highlight box | `undrr/highlight-box` | [Highlight box](https://mangrove.undrr.org/?path=/docs/components-highlightbox--docs) | Call-out with inner blocks |
627
+ | Quote highlight | `undrr/undrr-quote-highlight-block` | [Quote highlight](https://mangrove.undrr.org/?path=/docs/components-quotehighlight--docs) | Quote with attribution |
628
+ | Social share | `undrr/undrr-social-share-block` | [Share buttons](https://mangrove.undrr.org/?path=/docs/components-buttons-sharebuttons--docs) | No attributes |
629
+ | Gallery | `undrr/gallery` | [Gallery](https://mangrove.undrr.org/?path=/docs/components-gallery--docs) | Hydrated from `data-mg-gallery-data` |
630
+ | UNDRR Call to Action | `undrr/cta-band` | [CTA](https://mangrove.undrr.org/?path=/docs/components-cta--docs) | Full-width call-to-action band |
631
+ | UNDRR Notice | `undrr/notice` | [Notice](https://mangrove.undrr.org/?path=/docs/components-notice-notice--docs) | Deadlines, corrections, milestones |
632
+ | UNDRR Hub Header | `undrr/hub-header` | Hub header, shown in [Content hub](https://mangrove.undrr.org/?path=/docs/patterns-content-hub--docs) | Persistent identity and section links for a hub |
633
+ | UNDRR Search Widget | `undrr/search-widget` | [Syndicated search](https://mangrove.undrr.org/?path=/docs/components-syndicated-search--docs) | See [Search widget editor configuration](https://mangrove.undrr.org/llms-search-widget.txt) |
634
+ | UNDRR Search Bar Container, UNDRR Search Facets Container | `undrr/search-bar-target`, `undrr/search-facets-target` | Regions for the search widget | Place the search input or facets elsewhere on the page |
635
+
636
+ The module also extends some core blocks rather than adding new ones:
637
+
638
+ - Every core block gains an `undrrUtilityClasses` attribute, which is how Mangrove utility classes such as `mg-container-full-width` reach the saved markup.
639
+ - **Columns** gains a **Mangrove grid** toggle. Columns inserted from the layout picker start on the grid: the block saves `"mgGrid":true` and adds [`mg-grid mg-grid__col-N`](https://mangrove.undrr.org/?path=/docs/design-decisions-grid-layout--docs) to the wrapper, and columns stack below 900px. Existing columns, and hand-written markup without `mgGrid`, keep the standard Gutenberg flex columns. The layout examples in these guides use the flex form, which is what most existing pages use.
640
+ - **Details** and **Table** gain an opt-in **Mangrove presentation** panel. Details keep their native disclosure behaviour. Tables offer compact density, stripes, borders and a named, keyboard-focusable scrolling region; give tables proper header cells and a descriptive caption, because these controls do not add sorting or stacked mobile labels.
641
+
642
+ The **UNDRR pages** pattern category in the inserter provides a reading page with contents, an initiative overview, a publication collection and a frequently asked questions section. Patterns insert ordinary editable blocks, so replace the starter text, figures, images and link destinations before publishing.
643
+
644
+ Deprecated blocks remain valid on existing pages but should not be used in new content. Nor should the Drupal page title block (`drupalblock/page-title-block`): use a level 1 heading block instead.
645
+
646
+ | Deprecated block | Use instead |
647
+ | --- | --- |
648
+ | Tabs V1 (`undrr/undrr-tabs-block`) | Tabs V2 (`undrr/undrr-tabs-v2-block`) |
649
+ | Tab section V1 (`undrr/undrr-tabs-section`) | Tab section V2 (`undrr/undrr-tabs-v2-section`) |
650
+
651
+ ## Serialization rules
652
+
653
+ Drupal Gutenberg 3.x does not always serialize the way WordPress Gutenberg does. Markup written the WordPress way causes validation warnings or block recovery prompts.
654
+
655
+ ### Wrap HTML comments in `wp:html`
656
+
657
+ The block parser is confused by bare HTML comments between blocks. To keep an editorial note in the saved page, wrap it in a `wp:html` block:
658
+
659
+ ```html
660
+ <!-- wp:html -->
661
+ <!-- Editorial note: replace the placeholder images before publishing. -->
662
+ <!-- /wp:html -->
663
+ ```
664
+
665
+ A notes block like this at the top of a page is a useful place for editors to leave instructions for each other.
666
+
667
+ ### Headings
668
+
669
+ Level 2 is the default, so `{"level":2}` can be omitted. An anchor goes in the HTML `id`; `{"anchor":"my-section"}` in the block comment also works and survives round trips through the editor better.
670
+
671
+ ```html
672
+ <!-- wp:heading -->
673
+ <h2 class="wp-block-heading" id="my-section">Section heading</h2>
674
+ <!-- /wp:heading -->
675
+ ```
676
+
677
+ ### Font sizes write two classes
678
+
679
+ A `fontSize` attribute writes the Gutenberg class and a paired Mangrove utility class from a fixed map, so the markup also renders correctly where Mangrove CSS is loaded without the Gutenberg styles:
680
+
681
+ | `fontSize` | Saved classes |
682
+ | --- | --- |
683
+ | `small` | `has-small-font-size mg-u-font-size-250` |
684
+ | `regular` | `has-regular-font-size mg-u-font-size-300` |
685
+ | `medium` | `has-medium-font-size mg-u-font-size-400` |
686
+ | `large` | `has-large-font-size mg-u-font-size-500` |
687
+ | `huge` | `has-huge-font-size mg-u-font-size-800` |
688
+
689
+ On `wp:buttons`, Gutenberg also adds `has-custom-font-size`.
690
+
691
+ ```html
692
+ <!-- wp:heading {"level":1,"fontSize":"huge"} -->
693
+ <h1 class="wp-block-heading has-huge-font-size mg-u-font-size-800">Page title</h1>
694
+ <!-- /wp:heading -->
695
+ ```
696
+
697
+ Older pages set `{"className":"has-large-font-size"}` on paragraphs instead. That still renders, but new content should use the `fontSize` attribute from the editor's typography panel.
698
+
699
+ ### Buttons carry Mangrove classes
700
+
701
+ `wp:button` writes the core `wp-element-button` class and a Mangrove button class. The default style maps to `mg-button-primary`; the **Outline** style maps to `mg-button-secondary`. `mg-button-arrow` appears only in the hero block's own buttons, never in `wp:button`.
702
+
703
+ ```html
704
+ <!-- wp:buttons {"layout":{"type":"flex","justifyContent":"left"}} -->
705
+ <div class="wp-block-buttons"><!-- wp:button -->
706
+ <div class="wp-block-button"><a class="wp-block-button__link wp-element-button mg-button mg-button-primary" href="/path">Primary action</a></div>
707
+ <!-- /wp:button -->
708
+
709
+ <!-- wp:button {"className":"is-style-outline"} -->
710
+ <div class="wp-block-button is-style-outline"><a class="wp-block-button__link wp-element-button mg-button mg-button-secondary" href="/path">Secondary action</a></div>
711
+ <!-- /wp:button --></div>
712
+ <!-- /wp:buttons -->
713
+ ```
714
+
715
+ `is-style-primary is-style-outline` together still produce `mg-button-secondary`; the outline style wins.
716
+
717
+ ### Lists
718
+
719
+ `wp:list` is saved with an explicit `className` even though `wp-block-list` is its default, and every item needs its own `wp:list-item` wrapper. Bare `<li>` elements fail validation.
720
+
721
+ ```html
722
+ <!-- wp:list {"className":"wp-block-list"} -->
723
+ <ul class="wp-block-list"><!-- wp:list-item -->
724
+ <li>First item</li>
725
+ <!-- /wp:list-item -->
726
+
727
+ <!-- wp:list-item -->
728
+ <li>Second item with a <a href="https://www.undrr.org">link</a></li>
729
+ <!-- /wp:list-item --></ul>
730
+ <!-- /wp:list -->
731
+ ```
732
+
733
+ ### Separators and spacers
734
+
735
+ ```html
736
+ <!-- wp:separator {"opacity":"css"} -->
737
+ <hr class="wp-block-separator has-css-opacity"/>
738
+ <!-- /wp:separator -->
739
+
740
+ <!-- wp:spacer {"height":"40px"} -->
741
+ <div style="height:40px" aria-hidden="true" class="wp-block-spacer"></div>
742
+ <!-- /wp:spacer -->
743
+ ```
744
+
745
+ ### Images from the media library
746
+
747
+ An image inserted from the Drupal media library records the Drupal file in a `mediaAttrs` object and mirrors it as `data-*` attributes on the `<img>`. Captions use `wp-element-caption`.
748
+
749
+ ```html
750
+ <!-- wp:image {"id":95062,"sizeSlug":"full","linkDestination":"none","mediaAttrs":{"data-entity-type":"file","data-entity-uuid":"c406fed6-d9d1-413c-9ed0-f067d4c2f93f","data-image-style":"original"}} -->
751
+ <figure class="wp-block-image size-full"><img src="/sites/default/files/2025-10/photo.jpg" alt="Alt text" class="wp-image-95062" data-entity-type="file" data-entity-uuid="c406fed6-d9d1-413c-9ed0-f067d4c2f93f" data-image-style="original"/><figcaption class="wp-element-caption">Caption. Photo: UNDRR</figcaption></figure>
752
+ <!-- /wp:image -->
753
+ ```
754
+
755
+ When drafting without a real media item, use a placeholder `src` and leave out `mediaAttrs`; the editor fills them in when an image is chosen.
756
+
757
+ Image paths start with `/sites/default/files/`. A Drupal `public://` path becomes `/sites/default/files/`, and spaces in file names are URL-encoded.
758
+
759
+ ### Media URLs are not stored in the block comment
760
+
761
+ For `undrr/undrr-card` and `undrr/undrr-hero-block`, `mediaURL` is read back from the `src` of the saved `<img>`, so it does not belong in the block comment; the editor drops it there on the next save. `mediaID` and the alt text attribute (`mediaAlt` on cards, `mediaAltText` on heroes) do belong in the comment.
762
+
763
+ ### Special characters
764
+
765
+ In the JSON block comment, characters can be written literally when pasting: `"Climate & Disaster"`. In the saved HTML, use entities: `Climate &amp; Disaster`, which matches what the blocks' `save()` functions produce.
766
+
767
+ When the editor saves, it escapes `<`, `>`, `&` and `"` inside attribute values as Unicode sequences (`\u003c`, `\u003e`, `\u0026`, `\u0022`), so an attribute that holds HTML, such as a hero `summaryText` with a link, reads `\u003ca href=\u0022…\u0022\u003e` in the block comment. Write it that way when composing by hand: an unescaped `"` inside an attribute value ends the JSON string and breaks the block.
768
+
769
+ ### Section wrappers use columns, not groups
770
+
771
+ `wp:group` breaks when it is used as a standalone section or background wrapper. Use `wp:columns` with a single `wp:column` child instead:
772
+
773
+ ```html
774
+ <!-- wp:columns {"backgroundColor":"undrr-light-grey","undrrUtilityClasses":["mg-container-full-width"]} -->
775
+ <div class="wp-block-columns has-undrr-light-grey-background-color has-background mg-container-full-width"><!-- wp:column -->
776
+ <div class="wp-block-column">
777
+
778
+ [section content]
779
+
780
+ </div>
781
+ <!-- /wp:column --></div>
782
+ <!-- /wp:columns -->
783
+ ```
784
+
785
+ One exception works: `wp:group {"layout":{"type":"constrained"}}` nested inside a `wp:column` of such a wrapper, which holds the section content to the default content width without percentage columns. [Building landing pages](#section-backgrounds) shows both.
786
+
787
+ ## Rendering constraints
788
+
789
+ Valid markup can still render wrongly because of the Mangrove CSS and scripts a site loads. Several limits of older builds are fixed in current Mangrove, so check which Mangrove version the site loads before applying a workaround. Page-level CSS goes in a `wp:html` block containing a `<style>` element, and each workaround should be removed once the site runs a version with the fix.
790
+
791
+ - **Root font size.** Mangrove 1.x sites use a 10px root (`html { font-size: 62.5% }`), so in page-level CSS `1rem` is 10px: write `1.6rem` for 16px text and `1.4rem` for 14px. Mangrove 2.0 removes the 10px root and uses the browser-standard 16px, so on 2.0 write plain rem values. A rule written for the wrong root looks as if it was ignored.
792
+ - **Stats card column count.** Before Mangrove 1.8.2 the grid had classes for 1–6 columns only, and a stats card with seven or more stats collapsed to one stacked column. Current Mangrove supports 1–12 columns, and the block saves `mg-grid--auto-fit` for larger sets. Keep groups small enough for values and labels to stay readable on a phone.
793
+ - **Icon cards.** Before Icon card 1.4, `centered: true` centred the label but left the glyph pinned to the left, and `iconSize` was dropped at hydration. Current Mangrove centres both and applies custom glyph sizes in the editor and on the published card.
794
+ - **Cards without an image.** Vertical and horizontal cards hang their border, background and padding on the image area. With no image they render as bare text. Give them an image, or choose another pattern for imageless content.
795
+ - **Highlight box primary tone.** Before Highlight box 1.2, text inside the dark blue `primary` tone inherited near-black and failed contrast. Current Mangrove sets the text to white.
796
+ - **Hero without an image.** Since Hero 1.9.0 the background layout shows the photograph as a banner above the copy on narrow screens. The block adds `mg-hero--no-image` to a background hero saved without an image, so the empty banner collapses. Heroes saved before the block added the class still carry the empty banner until they are saved again.
797
+
798
+ ## Block reference
799
+
800
+ Attributes and current markup for each UNDRR block. Blocks whose markup is long or depends on the media library (Gallery, Call to Action, Notice, Hub Header, Search Bar Container, Search Facets Container) are best built in the visual editor; their attributes are listed in the block's sidebar.
801
+
802
+ ### Hero
803
+
804
+ `undrr/undrr-hero-block` renders the [Hero](https://mangrove.undrr.org/?path=/docs/components-hero-hero--docs) component. [Building landing pages](#choosing-a-hero) covers when to use each layout.
805
+
806
+ | Attribute | Values | Notes |
807
+ | --- | --- | --- |
808
+ | `layout` | `background` (default), `split` | Prefer `split` for new pages. `background` is still the default, so set `layout` explicitly |
809
+ | `splitRatio` | `2/3` (default), `1/2`, `1/3` | Split only. The fraction is the **content** column: `2/3` is text-led, `1/3` is media-led. Saves `mg-hero--split-2-3`, `-1-2` or `-1-3`; an unrecognized value falls back to `2-3` |
810
+ | `mediaType` | `image` (default), `video`, `html` | Split only. `background` accepts an image only |
811
+ | `headingLevel` | `h1` (default), `h2`, `h3`, `header` | Use `h1` when the hero opens the page. `header` (no heading level) saves the title in a `<span>` |
812
+ | `title` | Plain text | Accepts `<br>` and `&nbsp;` for line breaks |
813
+ | `summaryText` | Rich text | Saved raw when it holds inline markup only; wrap it in `<p>` in the attribute to get a `<p>` in the output |
814
+ | `labelText`, `labelLink`, `toggleLabel` | Text, URL, boolean | Short eyebrow label above the title |
815
+ | `primaryButtonText`, `primaryButtonLink` | Text, URL | The title links to `primaryButtonLink`; there is no separate title link |
816
+ | `secondaryButtonText`, `secondaryButtonLink`, `toggleButtonSecondary` | Text, URL, boolean | Second button |
817
+ | `tertiaryButtonText`, `tertiaryButtonLink`, `toggleButtonTertiary` | Text, URL, boolean | Third button |
818
+ | `openTab` | Boolean | Opens every hero link in a new tab |
819
+ | `overlayBackgroundColor` | `primary`, `secondary`, `tertiary`, `quaternary` | Saves `mg-hero--{value}`, except `primary`, which saves `mg-hero--` with an empty suffix; unset saves `mg-hero--undefined` |
820
+ | `mediaID`, `mediaAltText` | Media ID, text | Image media |
821
+ | `videoEmbedUrl`, `videoTitle` | URL, text | Video media. Use the `/embed/` URL; a watch URL renders a refused frame. `videoTitle` is the iframe's accessible name and is required |
822
+ | `customHtml` | HTML string | HTML media. Rendered verbatim, so it must be sanitized before saving. A bare `<figure>` with `<img>` and `<figcaption>` gets an attribution overlay |
823
+
824
+ The `heroType` option (`parent` or `child`) was retired in April 2026; leave it unset.
825
+
826
+ Current split hero with an image and no label, as the editor saves it today:
827
+
828
+ ```html
829
+ <!-- wp:undrr/undrr-hero-block {"title":"Monitoring the Sendai Framework","summaryText":"Strong accountability is a cornerstone of the \u003ca href=\u0022https://www.undrr.org/implementing-sendai-framework/what-sendai-framework\u0022\u003eSendai Framework for Disaster Risk Reduction\u003c/a\u003e","primaryButtonText":"Go to the SFM analytics portal","primaryButtonLink":"https://sendaimonitor.undrr.org/analytics","layout":"split","splitRatio":"1/2","headingLevel":"h1","mediaType":"image","mediaID":"119162","mediaAltText":"Firefighters amongst a brush fire","undrrUtilityClasses":[]} -->
830
+ <section class="wp-block-undrr-undrr-hero-block mg-hero mg-hero--split mg-hero--split-1-2 mg-hero--undefined"><div class="mg-hero__split-grid mg-container"><article class="mg-hero__content"><header class="mg-hero__title"><h1 class="text-xxl"><a href="https://sendaimonitor.undrr.org/analytics">Monitoring the Sendai Framework</a></h1></header><div class="mg-hero__summaryText">Strong accountability is a cornerstone of the <a href="https://www.undrr.org/implementing-sendai-framework/what-sendai-framework">Sendai Framework for Disaster Risk Reduction</a></div><div class="mg-hero__buttons"><a href="https://sendaimonitor.undrr.org/analytics" target="_self" rel="noreferrer" role="button" type="Primary" class="mg-button mg-button-primary mg-button-arrow">Go to the SFM analytics portal</a></div></article><div class="mg-hero__media"><img src="/sites/default/files/styles/ultrawide_16_6/public/2026-07/smoke-firefighters.jpg?h=c673cd1c&amp;itok=DmrYvrbd" alt="Firefighters amongst a brush fire" class="mg-hero__media-img" data-mg-media-id="119162"/></div></div></section>
831
+ <!-- /wp:undrr/undrr-hero-block -->
832
+ ```
833
+
834
+ Details that trip up hand-written hero markup:
835
+
836
+ - `mg-hero--undefined` when `overlayBackgroundColor` is unset. Heroes saved before the current block version have a trailing space after it; both forms validate.
837
+ - No `mg-hero__meta` element when there is no label.
838
+ - The title is `<h1 class="text-xxl"><a href="…">Text</a></h1>`.
839
+ - The `<img>` carries `data-mg-media-id`, and its `src` is a Drupal image style derivative with an `?h=…&itok=…` query. Copy the URL the media library generates rather than writing one. The `mediaID` and URL in the example above are illustrative.
840
+ - To draft a split image hero without a real media ID, leave `mediaID` and `mediaAltText` out of the block comment and leave out the whole `<div class="mg-hero__media">` element. The block saves no media column until an image is chosen, so the markup still validates; choose the image in the editor before publishing.
841
+
842
+ Current split hero with a video, media-led (`1/3`):
843
+
844
+ ```html
845
+ <!-- wp:undrr/undrr-hero-block {"title":"El Niño","summaryText":"A shift in the Pacific Ocean that raises the odds of drought, flood, heat and fire across large parts of the world.","primaryButtonText":"Explore the evidence on PreventionWeb","primaryButtonLink":"https://www.preventionweb.net/hubs/el-nino","layout":"split","splitRatio":"1/3","headingLevel":"h1","mediaType":"video","videoEmbedUrl":"https://www.youtube.com/embed/FVTESdSeWnw","videoTitle":"What can be done to protect Southern Africa from El Niño?","undrrUtilityClasses":[]} -->
846
+ <section class="wp-block-undrr-undrr-hero-block mg-hero mg-hero--split mg-hero--split-1-3 mg-hero--undefined"><div class="mg-hero__split-grid mg-container"><article class="mg-hero__content"><header class="mg-hero__title"><h1 class="text-xxl"><a href="https://www.preventionweb.net/hubs/el-nino">El Niño</a></h1></header><div class="mg-hero__summaryText">A shift in the Pacific Ocean that raises the odds of drought, flood, heat and fire across large parts of the world.</div><div class="mg-hero__buttons"><a href="https://www.preventionweb.net/hubs/el-nino" target="_self" rel="noreferrer" role="button" type="Primary" class="mg-button mg-button-primary mg-button-arrow">Explore the evidence on PreventionWeb</a></div></article><div class="mg-hero__media mg-hero__media--video"><iframe src="https://www.youtube.com/embed/FVTESdSeWnw" title="What can be done to protect Southern Africa from El Niño?" class="mg-hero__media-iframe" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen=""></iframe></div></div></section>
847
+ <!-- /wp:undrr/undrr-hero-block -->
848
+ ```
849
+
850
+ Copy the iframe's `allow` list and `allowfullscreen` exactly; the block writes a fixed list and anything else fails validation. When a hero has both `mediaID` and `videoEmbedUrl`, the video wins and the image is ignored.
851
+
852
+ For a hero with a label, extra buttons or custom HTML media, build it in the visual editor and copy the result from the Code editor: those options change the saved structure in ways that are easy to get wrong by hand.
853
+
854
+ ### Card
855
+
856
+ `undrr/undrr-card` renders one of five Mangrove cards, chosen by `cardType`.
857
+
858
+ | `cardType` | Wrapper classes | Renders | Image style picked by the editor |
859
+ | --- | --- | --- | --- |
860
+ | `vc` (default) | `mg-card mg-card__vc` | [Vertical card](https://mangrove.undrr.org/?path=/docs/components-cards-vertical-card--docs) | `landscape_16_9` |
861
+ | `hc` | `mg-card mg-card__hc` | [Horizontal card](https://mangrove.undrr.org/?path=/docs/components-cards-horizontal-card--docs) | `landscape_16_9` |
862
+ | `book` | `mg-card mg-card__book` | [Book card](https://mangrove.undrr.org/?path=/docs/components-cards-book-card--docs) | `por` (portrait) |
863
+ | `hc_book` | `mg-card mg-card__hc mg-card-book__hc` | [Horizontal book card](https://mangrove.undrr.org/?path=/docs/components-cards-horizontal-book-card--docs) | `por` (portrait) |
864
+ | `icon` | `mg-card mg-card__icon` | [Icon card](https://mangrove.undrr.org/?path=/docs/components-cards-icon-card--docs) | `thumbnail` |
865
+
866
+ Every attribute except `title` is optional, and each element is saved only when its attribute is set: no image means no `mg-card__visual`, no label means no `mg-card__meta`.
867
+
868
+ | Attribute | Saved as |
869
+ | --- | --- |
870
+ | `title`, `titleLink` | `<header class="mg-card__title"><a href="{titleLink}">{title}</a></header>` |
871
+ | `labelText`, `labelLink` | `<div class="mg-card__meta"><a href="{labelLink}" class="mg-card__label">{labelText}</a></div>` |
872
+ | `summary` | `<div class="mg-card__summary">{summary}</div>` |
873
+ | `mediaID`, `mediaAlt` | `<div class="mg-card__visual"><img … class="mg-card__image" loading="lazy"/></div>`. Use `"mediaAlt":""` for a decorative cover |
874
+ | `primaryButtonText`, `primaryButtonLink` | `<a class="mg-button mg-button-primary mg-button-arrow" role="button" type="Primary">` |
875
+ | `colorVariant` | `mg-card--{value}` for `secondary`, `tertiary` or `quaternary`; `primary` (the default) saves no class |
876
+ | `plainTitle` | `mg-card--plain-title`, which drops the title link's underline and hover colour |
877
+
878
+ Vertical, horizontal and book cards save a single `<article>` that carries both the block class and the Mangrove card classes (`wp-block-undrr-undrr-card mg-card mg-card__vc`). Icon cards keep an inner `<div class="mg-card mg-card__icon">`, because their hydration reads it. The saved order is `mg-card__visual` before `mg-card__content`, and inside the content the meta, then the title, then the summary.
879
+
880
+ Vertical card with image and summary:
881
+
882
+ ```html
883
+ <!-- wp:undrr/undrr-card {"title":"Drought","titleLink":"/hazard-information-profiles","summary":"Rainfall deficits tend to concentrate in Central America's Dry Corridor, parts of southern Africa, Australia and Southeast Asia.","mediaID":"118479","mediaAlt":"A farmer in Mozambique receives agricultural inputs"} -->
884
+ <article class="wp-block-undrr-undrr-card mg-card mg-card__vc"><div class="mg-card__visual"><img src="/sites/default/files/2026-06/example.jpg" alt="A farmer in Mozambique receives agricultural inputs" data-mg-media-id="118479" class="mg-card__image" loading="lazy"/></div><div class="mg-card__content"><header class="mg-card__title"><a href="/hazard-information-profiles">Drought</a></header><div class="mg-card__summary">Rainfall deficits tend to concentrate in Central America's Dry Corridor, parts of southern Africa, Australia and Southeast Asia.</div></div></article>
885
+ <!-- /wp:undrr/undrr-card -->
886
+ ```
887
+
888
+ Book card with a cover, and without one:
889
+
890
+ ```html
891
+ <!-- wp:undrr/undrr-card {"title":"Global Assessment Report 2024","titleLink":"https://www.undrr.org/gar/2024","cardType":"book","mediaAlt":""} -->
892
+ <article class="wp-block-undrr-undrr-card mg-card mg-card__book"><div class="mg-card__visual"><img src="/sites/default/files/2024-06/gar2024-cover.jpg" alt="" class="mg-card__image" loading="lazy"/></div><div class="mg-card__content"><header class="mg-card__title"><a href="https://www.undrr.org/gar/2024">Global Assessment Report 2024</a></header></div></article>
893
+ <!-- /wp:undrr/undrr-card -->
894
+
895
+ <!-- wp:undrr/undrr-card {"title":"Document title","titleLink":"https://www.undrr.org/publication/example","cardType":"book"} -->
896
+ <article class="wp-block-undrr-undrr-card mg-card mg-card__book"><div class="mg-card__content"><header class="mg-card__title"><a href="https://www.undrr.org/publication/example">Document title</a></header></div></article>
897
+ <!-- /wp:undrr/undrr-card -->
898
+ ```
899
+
900
+ Icon cards are the standard pattern for partner logo walls. They add `imageScale` (`"full"` fills the card), `centered` and `variant`, and the `<article>` carries four `data-mg-icon-card*` attributes that the component hydrates from. An icon card can show a Mangrove icon instead of an image through the `icon` attribute (for example `"icon":"mg-icon mg-icon-globe"`); see the [Icons gallery](https://mangrove.undrr.org/?path=/docs/components-icons--docs) for names.
901
+
902
+ ```html
903
+ <!-- wp:undrr/undrr-card {"title":"WMO","titleLink":"https://wmo.int/","mediaID":"116764","mediaAlt":"WMO","cardType":"icon","imageScale":"full","centered":true} -->
904
+ <article class="wp-block-undrr-undrr-card" data-mg-icon-card="" data-mg-icon-card-data="[{&quot;imgback&quot;:&quot;/sites/default/files/2026-04/wmo-logo.png&quot;,&quot;imgalt&quot;:&quot;WMO&quot;,&quot;iconSize&quot;:72,&quot;imageScale&quot;:&quot;full&quot;,&quot;title&quot;:&quot;WMO&quot;,&quot;srOnlyTitle&quot;:false,&quot;link&quot;:&quot;https://wmo.int/&quot;,&quot;buttonType&quot;:&quot;Primary&quot;}]" data-mg-icon-card-centered="true" data-mg-icon-card-variant="default"><div class="mg-card mg-card__icon mg-card__icon--centered"><div class="mg-card__visual"><img src="/sites/default/files/2026-04/wmo-logo.png" alt="WMO" data-mg-media-id="116764" class="mg-card__image mg-card__image--full"/></div><div class="mg-card__content"><header class="mg-card__title"><a href="https://wmo.int/">WMO</a></header></div></div></article>
905
+ <!-- /wp:undrr/undrr-card -->
906
+ ```
907
+
908
+ For an organization with no usable logo, leave out `mediaID` and the image; the card saves a text-only tile. Recent block versions add further keys to `data-mg-icon-card-data` (`icon`, `label`, `summaryText`, `linkText`, `button`) and save `imageScale` as `null` when it is unset, so copy icon cards from the editor when using those options.
909
+
910
+ ### Stats card
911
+
912
+ `undrr/stats-card` renders the [Stats card](https://mangrove.undrr.org/?path=/docs/components-cards-stats-card--docs). Attributes: `title`, `variant` (`default`, `compact`, `highlighted`, `negative`) and `stats`, an array of `{icon, label, value, bottomLabel, summaryText, link}`.
913
+
914
+ ```html
915
+ <!-- wp:undrr/stats-card {"title":"Global reporting snapshot","stats":[…]} -->
916
+ <section class="wp-block-undrr-stats-card" data-mg-stats-card="" data-stats="[…]" data-variant="default" data-title="Global reporting snapshot"><div class="mg-stats-card mg-stats-card--default"><h2 class="mg-stats-card__title">Global reporting snapshot</h2><div class="mg-grid mg-grid__col-3">
917
+ <article class="mg-stats-card-item mg-card">…</article>
918
+ </div></div></section>
919
+ <!-- /wp:undrr/stats-card -->
920
+ ```
921
+
922
+ - With no `title`, the block saves no `<h2>` and no `data-title`. That makes single-stat cards usable as items in a scroll container.
923
+ - The stats sit in an `mg-stats-card mg-stats-card--{variant}` wrapper, and the grid is saved with its column class: `mg-grid__col-N` for 1–12 stats, `mg-grid--auto-fit` above that.
924
+ - Older pages use earlier formats: a grid without a column class, or everything in one `data-mg-stats-card-data` object. They still validate and render, but new markup should use the format above. Enter the stats in the block sidebar rather than writing the JSON by hand.
925
+
926
+ ### Tabs
927
+
928
+ `undrr/undrr-tabs-v2-block` holds `undrr/undrr-tabs-v2-section` children and renders [Tabs](https://mangrove.undrr.org/?path=/docs/components-tabs--docs).
929
+
930
+ | Attribute | Block | Effect |
931
+ | --- | --- | --- |
932
+ | `tabOrientation` | Tabs | `horizontal` (default) or `stacked` (an accordion) |
933
+ | `hasFullWidthBackground` | Tabs | Full-width background band |
934
+ | `defaultOpen` | Tabs, stacked only | **Default open state**: `default` (first section open), `true` (all open) or `false` (all closed); saves `data-mg-js-tabs-default-open` unless it is `default` |
935
+ | `filterable` | Tabs, stacked only | **Show filter input**: a keyword search field above the sections; saves `data-mg-js-tabs-filterable=""` |
936
+ | `filterPlaceholder` | Tabs, stacked only | Placeholder for that field |
937
+ | `singleOpen` | Tabs, stacked only | **Single open (accordion)**: only one section open at a time; saves `data-mg-js-tabs-single-open=""` |
938
+ | `id` | Section | Used raw in the link `href` and section `id`, prefixed with `mg-tabs__section-` |
939
+ | `label` | Section | Tab text, and the section's `<h2>` |
940
+ | `unlabelled` | Section | **Hide heading**: saves that `<h2>` as `mg-u-sr-only`, for when the tab label is already the visible heading |
941
+ | `defaultOpen` | Section | Opens this section first |
942
+
943
+ Serialization details:
944
+
945
+ - The outer `<div>` has only Mangrove classes, not the `wp-block-undrr-undrr-tabs-v2-block` class, and `mg-tabs__list` has a trailing space in its `class`.
946
+ - The editor writes a `dirty` attribute holding a timestamp when the block is saved. It does not appear in the saved HTML.
947
+ - Boolean options save as empty-string attributes (`=""`), not `="true"`, and the stacked-only options are dropped from the output of a horizontal tab set.
948
+ - Each section saves **two sibling `<li>` elements**: a link item and a content item. Writing one `<li>` per section is the most common cause of an invalid tabs block.
949
+
950
+ Horizontal tabs with one section:
951
+
952
+ ```html
953
+ <!-- wp:undrr/undrr-tabs-v2-block -->
954
+ <div class="mg-tabs mg-tabs--horizontal" data-mg-js-tabs="true" data-mg-js-tabs-variant="horizontal"><ul class="mg-tabs__list "><!-- wp:undrr/undrr-tabs-v2-section {"id":"overview","label":"Overview","defaultOpen":true} -->
955
+ <li class="mg-tabs__item"><a class="mg-tabs__link" href="#mg-tabs__section-overview" data-mg-js-tabs-default="true" role="tab">Overview</a></li><li class="mg-tabs-content" data-mg-js-tabs-content="true"><section class="mg-tabs__section" id="mg-tabs__section-overview"><h2>Overview</h2><!-- wp:paragraph -->
956
+ <p>Section content.</p>
957
+ <!-- /wp:paragraph --></section></li>
958
+ <!-- /wp:undrr/undrr-tabs-v2-section --></ul></div>
959
+ <!-- /wp:undrr/undrr-tabs-v2-block -->
960
+ ```
961
+
962
+ Stacked tabs with a keyword filter, the right tool for long reference content such as frequently asked questions:
963
+
964
+ ```html
965
+ <!-- wp:undrr/undrr-tabs-v2-block {"tabOrientation":"stacked","singleOpen":true,"filterable":true,"filterPlaceholder":"Search targets, indicators and topics"} -->
966
+ <div class="mg-tabs mg-tabs--stacked" data-mg-js-tabs="true" data-mg-js-tabs-variant="stacked" data-mg-js-tabs-single-open="" data-mg-js-tabs-filterable="" data-mg-js-tabs-filter-placeholder="Search targets, indicators and topics"><ul class="mg-tabs__list "><!-- wp:undrr/undrr-tabs-v2-section {"id":"target-a","label":"Target A: Mortality"} -->
967
+ <li class="mg-tabs__item"><a class="mg-tabs__link" href="#mg-tabs__section-target-a" data-mg-js-tabs-default="false" role="tab">Target A: Mortality</a></li><li class="mg-tabs-content" data-mg-js-tabs-content="true"><section class="mg-tabs__section" id="mg-tabs__section-target-a"><h2>Target A: Mortality</h2><!-- wp:paragraph -->
968
+ <p>Section content.</p>
969
+ <!-- /wp:paragraph --></section></li>
970
+ <!-- /wp:undrr/undrr-tabs-v2-section --></ul></div>
971
+ <!-- /wp:undrr/undrr-tabs-v2-block -->
972
+ ```
973
+
974
+ The filter matches section labels, so write labels with the words a reader would search for.
975
+
976
+ ### Table of contents
977
+
978
+ `undrr/undrr-table-of-contents-block` renders the [Table of contents](https://mangrove.undrr.org/?path=/docs/components-navigation-table-of-contents--docs) from the page's `<h2>` headings. Attributes: `title` (default "On this page") and `showTitle`. It is not self-closing: it needs its `<section>`, and the saved markup always includes `data-mg-table-of-contents-skip-auto-init="true"`, which stops the Mangrove script initializing it twice.
979
+
980
+ ```html
981
+ <!-- wp:undrr/undrr-table-of-contents-block -->
982
+ <section class="wp-block-undrr-undrr-table-of-contents-block mg-table-of-contents" data-mg-table-of-contents="true" data-mg-table-of-contents-title="On this page" data-mg-table-of-contents-show-title="true" data-mg-table-of-contents-skip-auto-init="true"></section>
983
+ <!-- /wp:undrr/undrr-table-of-contents-block -->
984
+ ```
985
+
986
+ To leave a heading out of the list, add the `mg-table-of-contents--exclude` class to it through its utility classes or `className`:
987
+
988
+ ```html
989
+ <!-- wp:heading {"className":"mg-table-of-contents--exclude"} -->
990
+ <h2 class="wp-block-heading mg-table-of-contents--exclude">Introduction</h2>
991
+ <!-- /wp:heading -->
992
+ ```
993
+
994
+ ### On this page navigation
995
+
996
+ `undrr/undrr-on-this-page-nav-block` renders the [On this page nav](https://mangrove.undrr.org/?path=/docs/components-navigation-on-this-page-nav--docs), a sticky bar built from the page headings when the page loads.
997
+
998
+ | Attribute | Default | Notes |
999
+ | --- | --- | --- |
1000
+ | `depth` | `"2"` | `"2"` for H2 only, `"3"` adds H3, `"4"` adds H4 |
1001
+ | `contentSelector` | `".landing-page-body"` | Container scanned for headings |
1002
+ | `label` | `"On this page"` | Text before the links |
1003
+ | `showCta`, `ctaText`, `ctaUrl` | `false`, empty, empty | Optional call-to-action link at the end of the bar |
1004
+
1005
+ ```html
1006
+ <!-- wp:undrr/undrr-on-this-page-nav-block {"showCta":true,"ctaText":"Download the concept note","ctaUrl":"/media/118609"} -->
1007
+ <nav class="wp-block-undrr-undrr-on-this-page-nav-block mg-on-this-page-nav" data-mg-on-this-page-nav="true" data-mg-on-this-page-nav-depth="2" data-mg-on-this-page-nav-content=".landing-page-body" data-mg-on-this-page-nav-label="On this page"><a href="/media/118609" class="mg-on-this-page-nav__cta">Download the concept note</a></nav>
1008
+ <!-- /wp:undrr/undrr-on-this-page-nav-block -->
1009
+ ```
1010
+
1011
+ Without the call to action, the `<nav>` is empty.
1012
+
1013
+ Some older pages build this bar by hand in a `wp:html` block marked with a `prototype: mga-nav-on-this-page` comment (tracked in [undrr/web-backlog#337](https://gitlab.com/undrr/web-backlog/-/issues/337)). Use the block for new pages.
1014
+
1015
+ ### Show more button
1016
+
1017
+ `undrr/undrr-show-more-button` renders a [Show more](https://mangrove.undrr.org/?path=/docs/components-showmore--docs) toggle that collapses another block. Attributes: `targetSelector` (a class selector on the block to collapse), `labelCollapsed`, `labelOpen`, `collapsedHeight` (pixels) and `buttonStyle` (`primary` or `secondary`). `collapsedHeight` defaults to 200; any other value saves a `<style>` element that sets `--mg-show-more-height` on the target.
1018
+
1019
+ ```html
1020
+ <!-- wp:undrr/undrr-show-more-button {"targetSelector":".show-more-target-k7q2xa","collapsedHeight":300} -->
1021
+ <div class="wp-block-undrr-undrr-show-more-button"><style>.show-more-target-k7q2xa{--mg-show-more-height:300px}</style><a href="#" class="mg-button mg-button-primary mg-show-more--button" data-mg-show-more="true" data-mg-show-more-target=".show-more-target-k7q2xa" data-mg-show-more-label-collapsed="Show more" data-mg-show-more-label-open="Show less">Show more</a></div>
1022
+ <!-- /wp:undrr/undrr-show-more-button -->
1023
+ ```
1024
+
1025
+ [Building landing pages](#show-more) has the full layout with the target block.
1026
+
1027
+ ### Scroll container
1028
+
1029
+ `undrr/undrr-scroll-container` renders a [Scroll container](https://mangrove.undrr.org/?path=/docs/components-scrollcontainer--docs) around its inner blocks. Each direct child becomes one scroll item.
1030
+
1031
+ | Attribute | Default | Effect |
1032
+ | --- | --- | --- |
1033
+ | `itemWidth` | `auto` | Width of each item. Set a value such as `"300px"`, or items shrink to their content |
1034
+ | `stepSize` | `300` | Pixels scrolled per arrow click. Set it a little larger than `itemWidth` so a click advances one item and the gap |
1035
+ | `showArrows` | `true` | Previous and next buttons |
1036
+ | `height`, `minWidth`, `padding` | `auto`, `auto`, `0` | Row height, minimum item width, inner padding |
1037
+ | `ariaLabel` | Empty | Accessible name for the row, such as "Publications" or "Partners"; saved as `data-aria-label` only when set |
1038
+
1039
+ The six layout attributes are saved as `data-*` attributes whether or not they differ from the default. Name every scroll container, so screen reader users can tell one collection from another.
1040
+
1041
+ ```html
1042
+ <!-- wp:undrr/undrr-scroll-container {"itemWidth":"300px","stepSize":320} -->
1043
+ <div class="wp-block-undrr-undrr-scroll-container mg-scroll" data-mg-scroll-container="" data-height="auto" data-min-width="auto" data-item-width="300px" data-padding="0" data-show-arrows="true" data-step-size="320"><div class="mg-scroll__content">
1044
+
1045
+ [inner blocks]
1046
+
1047
+ </div></div>
1048
+ <!-- /wp:undrr/undrr-scroll-container -->
1049
+ ```
1050
+
1051
+ ### Highlight box
1052
+
1053
+ `undrr/highlight-box` renders a [Highlight box](https://mangrove.undrr.org/?path=/docs/components-highlightbox--docs) around its inner blocks. `tone` is `default`, `primary` or `secondary`; `layout` is `full` (default), `centered`, `float-start` or `float-end`. Non-default values add `mg-highlight-box--{value}`.
1054
+
1055
+ ```html
1056
+ <!-- wp:undrr/highlight-box {"tone":"secondary","layout":"centered"} -->
1057
+ <div class="wp-block-undrr-highlight-box mg-highlight-box mg-highlight-box--secondary mg-highlight-box--centered"><!-- wp:heading {"level":3} -->
1058
+ <h3 class="wp-block-heading">Did you know?</h3>
1059
+ <!-- /wp:heading -->
1060
+
1061
+ <!-- wp:paragraph -->
1062
+ <p>[One short fact, with its source.]</p>
1063
+ <!-- /wp:paragraph --></div>
1064
+ <!-- /wp:undrr/highlight-box -->
1065
+ ```
1066
+
1067
+ ### Quote highlight
1068
+
1069
+ `undrr/undrr-quote-highlight-block` renders a [Quote highlight](https://mangrove.undrr.org/?path=/docs/components-quotehighlight--docs). Attributes: `attribution`, `attributionTitle`, `imageSrc`, `imageAlt`, `backgroundColor` (`light` or `dark`), `variant` (`line` or `image`) and `alignment`. The quote itself is inner paragraph blocks.
1070
+
1071
+ ```html
1072
+ <!-- wp:undrr/undrr-quote-highlight-block {"attribution":"Name Surname","attributionTitle":"Title and organization"} -->
1073
+ <div class="wp-block-undrr-undrr-quote-highlight-block mg-quote-highlight mg-quote-highlight--light mg-quote-highlight--line mg-quote-highlight--full "><div class="mg-quote-highlight__content"><blockquote class="mg-quote-highlight__quote"><div class="mg-quote-highlight__quote-text"><!-- wp:paragraph -->
1074
+ <p>Disaster risk reduction is everyone's business. It requires the engagement of all sectors and all people.</p>
1075
+ <!-- /wp:paragraph --></div></blockquote><div class="mg-quote-highlight__separator"></div><div class="mg-quote-highlight__attribution"><div class="mg-quote-highlight__attribution-wrapper"><div class="mg-quote-highlight__attribution-text"><p class="mg-quote-highlight__attribution-name">Name Surname</p><p class="mg-quote-highlight__attribution-title">Title and organization</p></div></div></div></div></div>
1076
+ <!-- /wp:undrr/undrr-quote-highlight-block -->
1077
+ ```
1078
+
1079
+ For a pull quote with no attribution, a lighter pattern is in [Building landing pages](#quotes).
1080
+
1081
+ ### Social share
1082
+
1083
+ `undrr/undrr-social-share-block` has no attributes and renders [Share buttons](https://mangrove.undrr.org/?path=/docs/components-buttons-sharebuttons--docs).
1084
+
1085
+ ```html
1086
+ <!-- wp:undrr/undrr-social-share-block -->
1087
+ <div class="wp-block-undrr-undrr-social-share-block mg-share"><section data-mg-share-buttons="true"></section></div>
1088
+ <!-- /wp:undrr/undrr-social-share-block -->
1089
+ ```
1090
+
1091
+ ### Search widget
1092
+
1093
+ `undrr/search-widget` renders the [Syndicated search](https://mangrove.undrr.org/?path=/docs/components-syndicated-search--docs) widget. The block writes around 20 `data-*` attributes on a container with `data-undrr-search-widget="true"`, and a wrapper script in the Drupal theme reads them and mounts the Mangrove component. Mangrove's own hydration does not read that attribute; it is specific to the platform wrapper. Widgets saved before [undrr/web-backlog#2822](https://gitlab.com/undrr/web-backlog/-/work_items/2822) keep **Override with current website domain** and **Override with current page language** off through the block's deprecation; new widgets have both on. Configure it in the block sidebar rather than by hand; [Search widget editor configuration](https://mangrove.undrr.org/llms-search-widget.txt) documents every setting and the filter syntax, and has the [saved markup](https://mangrove.undrr.org/llms-search-widget.txt#saved-markup) of a new widget.
1094
+
1095
+ ### Core blocks used alongside the UNDRR blocks
1096
+
1097
+ **Video.** Use `wp:embed` with the ordinary watch URL; the Gutenberg text format swaps it for the player at render time. Put the caption in a paragraph after the embed, not in a `<figcaption>`.
1098
+
1099
+ ```html
1100
+ <!-- wp:embed {"url":"https://www.youtube.com/watch?v=VIDEO_ID","type":"rich","providerNameSlug":"youtube","responsive":true,"className":"wp-embed-aspect-16-9 wp-has-aspect-ratio"} -->
1101
+ <figure class="wp-block-embed is-type-rich is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
1102
+ https://www.youtube.com/watch?v=VIDEO_ID
1103
+ </div></figure>
1104
+ <!-- /wp:embed -->
1105
+
1106
+ <!-- wp:paragraph {"fontSize":"small"} -->
1107
+ <p class="has-small-font-size mg-u-font-size-250">Caption. Video: UNDRR</p>
1108
+ <!-- /wp:paragraph -->
1109
+ ```
1110
+
1111
+ **Drupal media.** `drupalmedia/drupal-media-entity` embeds a media entity (image, video or document) and is self-closing, because the server renders it. `viewMode` is a Drupal image style: `ultrawide_16_6`, `landscape_16_9`, `portrait_3_4`, `thumbnail` or `full`. A video media entity is worth it when the same video appears on several pages; for a one-off, `wp:embed` needs no media entity.
1112
+
1113
+ ```html
1114
+ <!-- wp:drupalmedia/drupal-media-entity {"mediaEntityIds":["84501"],"viewMode":"ultrawide_16_6"} /-->
1115
+ ```
1116
+
1117
+ **Page-level CSS.** A `wp:html` block with a `<style>` element holds CSS that no block attribute can express. Keep it at the end of the page body and keep it small; each rule is a page-level patch that someone has to find later.
1118
+
1119
+ ## Found a problem?
1120
+
1121
+ If something in this guide is wrong or out of date, such as markup that no longer matches what the editor saves, open an issue in the [Mangrove issue queue](https://github.com/PreventionWeb/undrr-mangrove/issues) (a GitHub account is needed).
1122
+
1123
+ ## Related documentation
1124
+
1125
+ - [Building landing pages](#building-landing-pages): page structure, layout patterns and component choice
1126
+ - [Search widget editor configuration](https://mangrove.undrr.org/llms-search-widget.txt): search widget settings and filter syntax
1127
+ - [Landing page patterns](https://mangrove.undrr.org/?path=/docs/patterns-landing-pages--docs): topic, report and collection index examples
1128
+ - [Hydration guide](https://mangrove.undrr.org/?path=/docs/getting-started-integration-hydration-guide--docs): how Mangrove turns saved markup into interactive components
1129
+ - [Editorial manual](https://mangrove.undrr.org/llms-editorial-manual.txt): capitalization, punctuation, numbers, spelling and UNDRR terminology
1130
+
1131
+ ## Links
1132
+
1133
+ - Rendered version in Storybook (Building landing pages): https://mangrove.undrr.org/?path=/docs/patterns-building-landing-pages--docs
1134
+ - Source on GitHub (Building landing pages): https://github.com/PreventionWeb/undrr-mangrove/blob/main/docs/LANDING-PAGE-GUIDE.md
1135
+ - Rendered version in Storybook (Drupal Gutenberg integration): https://mangrove.undrr.org/?path=/docs/getting-started-integration-drupal-gutenberg--docs
1136
+ - Source on GitHub (Drupal Gutenberg integration): https://github.com/PreventionWeb/undrr-mangrove/blob/main/docs/DRUPAL-GUTENBERG.md
1137
+ - Search widget editor configuration: https://mangrove.undrr.org/llms-search-widget.txt
1138
+ - Editorial manual: https://mangrove.undrr.org/llms-editorial-manual.txt
1139
+ - Full component/library manifest: https://mangrove.undrr.org/llms.txt
1140
+ - Report a problem with this guide: https://github.com/PreventionWeb/undrr-mangrove/issues