Reuse the components, sections and application layouts already implemented in WedUploader. This guide helps developers make small improvements with the current HTML, CSS and JavaScript, without designing a new UI for every change.
Use the guide in this order. Start with the architecture below. Open a
component reference for individual controls, then choose a
reusable layout pattern . Copy it into the matching
page starter , keep its wrapper and dependencies, and replace only the sample content or feature handler.
Reference
What you reuse
Where it belongs
Page Starter
The document scaffold: head dependencies, shared navigation, content container and scripts.
A new Public or Application page.
Reusable Layout Pattern
A populated content section: existing components arranged as a form, table, card grid, FAQ or marketing section.
Inside the starter’s existing content area. It does not add another shell.
Component
One control or UI unit, with its states and behaviour.
Within a pattern or an existing page.
Thirteen implementation groups remain available in the sidebar. Preview frames load each example’s actual context styles separately, so Public and Application rules do not leak into each other. HTML, dependency order and short source notes sit below every example.
Architecture
This ZIP is a static HTML/CSS/JavaScript project. The product contexts below sit beside each other at the project root; Guest Album is part of Public. The Documentation has no separate component library or build step.
Actual path
Responsibility
Use when extending
index.html
Project entry with links to the supplied contexts.
Keep the sibling folder structure when extracting the ZIP.
assets/css/wu-foundation.css
assets/css/wu-components.css
assets/css/wu-form-controls.css
assets/css/wu-icons.css
Shared tokens, Bootstrap theme bridge, controls, component primitives and icon classes. wu-components.css imports Foundation.
Reuse variables and classes. Do not copy their rules into a page stylesheet.
assets/js/wu-core.js
assets/logo/
assets/icons/
Shared JavaScript helpers, brand identity and SVG icons.
Reference the shared file; respect paths relative to the page or stylesheet.
public/*.html
public/assets/css/
public/assets/js/
Marketing, content and entry pages. Public media stays in public/assets/images/ and public/assets/ornaments/.
components.css and public.css import shared styles. site-shell.css and navigation.js belong to Public navigation. Other CSS depends on the page.
public/guest-template-1.html
public/guest-template-2.html
public/guest-template-3.html
Three separate Guest Album templates. public/assets/css/guest-album.css and public/assets/js/guest-album.js supply their related feature architecture.
Preserve the chosen template’s .wu-guest, template class and body configuration. Guest is not a fourth top-level app.
application/*.html
application/assets/css/
application/assets/js/
application/assets/images/
Dashboard, Manage Album, Moderation and other signed-in layouts.
application-shell.css styles the shared shell; application-features.css adds page-scoped layouts. application-album.css and premium.css are context additions, not global replacements.
documentation/index.html
documentation/preview.html
documentation/assets/js/examples.js
documentation/starters/
This reference, isolated live previews, source/dependency catalog and the two page starters. SOURCE_MAP.json records provenance.
Documentation styles use doc-*. Preview hosting stays in Documentation; product styles are loaded from their original folders.
Dependency order & ownership
Bootstrap: the source uses Bootstrap 5.3.8 CSS before theme/context styles and its bundle before Bootstrap-dependent scripts. Load the bundle once; it includes Popper and owns dropdown, tab, modal and offcanvas lifecycle.
Public: keep the chosen page’s CSS order. The starter uses components.css, pages.css, responsive.css, site-shell.css, public-layout.css, public.css and shared icons. Homepage compositions additionally use homepage.css; Pricing details use pricing-enhanced.css. Each pattern lists its required order. navigation.js owns the Public menu. Page scroll animation is optional and its attributes are omitted from the new reusable examples.
Application: shared icons/components/forms → application-shell.css → application-features.css → required page CSS. For the page starter, scripts are Bootstrap → wu-core.js → application-shell.js → application.js. The shell controller owns navigation/profile; application.js owns feature flows and guided tour. Files such as album-ui.js, album-drawers.js, voicemail.js and moderation-tabs.js are only added where their markup is present.
Shared markup, page code: shared classes style controls; wrappers and body classes select context rules. Give new Application pages a distinct data-page. Reuse a demonstrated styling class when needed, but do not copy a business root ID such as albumRows just to get its appearance. Keep one owner per event instead of adding a second modal/offcanvas/tab controller.
Use the exact dependency block attached to a specimen when a layout needs page-level CSS. Asset Usage explains file references, and Page Starter Guidance provides the practical starting files and local-server instructions.
Color families
These swatches use CSS variables from assets/css/wu-foundation.css. Values are generated from that file, not copied from an older palette board.
--wu-gold-0#fffdf8
--wu-gold-50#fbf8f2
--wu-gold-100#f5ecdd
--wu-gold-300#dfc18e
--wu-gold-500#c19a5b
--wu-gold-700#806036
--wu-gold-900#453015
--wu-bronze-0#fdfbf8
--wu-bronze-50#FBF9F5
--wu-bronze-100#F1EADF
--wu-bronze-300#D3BEA1
--wu-bronze-500#AB8965
--wu-bronze-700#71563D
--wu-bronze-900#3E2E21
--wu-neutral-0#ffffff
--wu-neutral-50#faf9f7
--wu-neutral-100#f4f1ec
--wu-neutral-300#d8d1c6
--wu-neutral-500#958c80
--wu-neutral-700#59524a
--wu-neutral-900#2b2824
Semantic roles
Variable
Root declaration
Applied at this viewport
--wu-primary
var(--wu-gold-500)
var(--wu-gold-500)
--wu-primary-2
#8C7954
#8C7954
--wu-canvas
#fffefc
#fffefc
--wu-accessible-deep
#57412e
#57412e
--wu-warm-ink
#292723
#292723
--wu-success-500
#2f7a58
#2f7a58
--wu-warning-500
#c98916
#c98916
--wu-danger-500
#b23a3a
#b23a3a
--wu-info-500
#4e7484
#4e7484
Typography
A place for every memory.
Clear controls. Familiar language. Inter for product UI.
Variable
Root declaration
Applied at this viewport
--wu-font-sans
"Inter", ui-sans-serif, system-ui, -apple-system,
BlinkMacSystemFont, "Segoe UI", sans-serif
"Inter", ui-sans-serif,
system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
sans-serif
--wu-font-display
"Playfair Display", serif
"Playfair Display",
serif
--wu-text-xs
0.75rem
0.75rem
--wu-text-sm
0.875rem
0.875rem
--wu-text-md
1rem
1rem
--wu-text-lg
1.125rem
1.125rem
--wu-text-xl
1.5rem
1.5rem
--wu-text-2xl
clamp(1.875rem, 4vw, 3.25rem)
clamp(1.875rem, 4vw, 3.25rem)
--wu-leading-tight
1.08
1.08
--wu-leading-body
1.55
1.55
The source defines .wu-text-md-standard more than once; the later 48px rule wins. Prefer semantic heading markup and the named size tokens when introducing a small page extension.
Spacing, layout & shape
Variable
Root declaration
Applied at this viewport
--wu-space-0
0
0
--wu-space-1
0.125rem
0.125rem
--wu-space-2
0.25rem
0.25rem
--wu-space-3
0.375rem
0.375rem
--wu-space-4
0.5rem
0.5rem
--wu-space-6
0.75rem
0.75rem
--wu-space-8
1rem
1rem
--wu-space-10
1.25rem
1.25rem
--wu-space-12
1.5rem
1.5rem
--wu-space-16
2rem
2rem
--wu-space-20
2.5rem
2.5rem
--wu-space-24
3rem
3rem
--wu-space-32
4rem
4rem
--wu-space-40
5rem
5rem
--wu-space-48
6rem
6rem
--wu-space-64
8rem
8rem
--wu-radius-none
0
0
--wu-radius-xs
0.25rem
0.25rem
--wu-radius-sm
0.5rem
0.5rem
--wu-radius-md
0.75rem
0.75rem
--wu-radius-lg
1rem
1rem
--wu-radius-xl
1.5rem
1.5rem
--wu-radius-2xl
2rem
2rem
--wu-radius-full
999rem
999rem
--wu-border-subtle
rgba(47, 36, 26, 0.12)
rgba(47, 36, 26, 0.12)
--wu-border-strong
rgba(90, 64, 40, 0.28)
rgba(90, 64, 40, 0.28)
--wu-shadow-xs
0 1px 2px rgba(47, 36, 26, 0.05)
0 1px 2px rgba(47, 36, 26, 0.05)
--wu-shadow-sm
0 4px 12px rgba(47, 36, 26, 0.07)
0 4px 12px rgba(47, 36, 26, 0.07)
--wu-shadow-md
0 12px 28px rgba(47, 36, 26, 0.09)
0 12px 28px rgba(47, 36, 26,
0.09)
--wu-shadow-lg
0 24px 50px rgba(47, 36, 26, 0.12)
0 24px 50px rgba(47, 36, 26,
0.12)
--wu-shadow-xl
0 32px 80px rgba(47, 36, 26, 0.16)
0 32px 80px rgba(47, 36, 26,
0.16)
--wu-shadow-overlay
0 40px 96px rgba(31, 29, 27, 0.25)
0 40px 96px rgba(31, 29, 27,
0.25)
--wu-shadow-jumbo
0px 32px 80px 0px rgba(24, 22, 20, 0.051)
0px 32px 80px 0px rgba(24, 22, 20,
0.051)
--wu-container
1280px
1280px
--wu-container-reading
760px
760px
--wu-section-space
clamp(4rem, 8vw, 8rem)
clamp(4rem, 8vw, 8rem)
--wu-radius-pill
999px
999px
--wu-shadow-focus
0 0 0 3px rgba(193,154,91,.22)
0 0 0 3px rgba(193,154,91,.22)
--wu-space-5
20px
20px
--wu-space-30
120px
120px
Use the actual Bootstrap
.container,
.row,
.col-*, gap and display utilities. Public adds
.wu-container; Application uses
.wu-app → .wu-main → .wu-page. Do not substitute one context's wrapper for another.
Source naming notes
Use
wu-select,
wu-button-md,
wu-button--outline--light and
wu-icon--md for new reuse. Some source markup also carries
wu-sellect,
wu-button--md,
wu-button--outline-light,
wu-icon-md or
wu-icon--m without matching CSS rules. Existing excerpts retain source markers; these are not documented as supported aliases.
Responsive conventions & Bootstrap bridge
Application and current Public menu use desktop ≥1200px, tablet 768–1199px and mobile <768px. Individual layouts also have component-specific media queries; keep the source CSS with the component.
Variable
Root declaration
Applied at this viewport
--bs-body-font-family
var(--wu-font-sans)
var(--wu-font-sans)
--bs-body-color
var(--wu-neutral-900)
var(--wu-neutral-900)
--bs-body-bg
var(--wu-neutral-0)
var(--wu-neutral-0)
--bs-primary
var(--wu-accessible-deep)
var(--wu-accessible-deep)
--bs-primary-rgb
90, 64, 40
90, 64, 40
--bs-secondary
var(--wu-bronze-500)
var(--wu-bronze-500)
--bs-secondary-rgb
140, 121, 84
140, 121, 84
--bs-border-color
var(--wu-border-subtle)
var(--wu-border-subtle)
--bs-border-radius-sm
var(--wu-radius-sm)
var(--wu-radius-sm)
--bs-border-radius
var(--wu-radius-md)
var(--wu-radius-md)
--bs-border-radius-lg
var(--wu-radius-lg)
var(--wu-radius-lg)
--bs-link-color
var(--wu-gold-700)
var(--wu-gold-700)
--bs-link-hover-color
var(--wu-gold-900)
var(--wu-gold-900)
--bs-focus-ring-color
rgba(193, 154, 91, 0.24)
rgba(193, 154, 91, 0.24)
Bootstrap primitive color values can be bridged while context CSS changes component appearance. Preserve stylesheet order. Form-specific variables live in wu-form-controls.css; guest --guest-* variables live in guest-album.css.
These are different controllers with different roots. Public menu, Application shell, Bootstrap tabs and Bootstrap dropdowns are shown in separate previews.
Application tabs → mobile dropdown
Source: application/moderation.html · .wu-moderation-tabs + #pills-tabContent
Bootstrap Tab owns active tab/pane state; moderation-tabs.js synchronizes the mobile dropdown label/count.
Below 768px, the trigger list is hidden and the existing .wu-tab-select dropdown is shown.
Tab panels contain short labels in this navigation specimen; use actual feature content on the destination page.
HTML example
HTML
Copy HTML
<div class="wu-moderation-tabs mb-3">
<ul
class="nav nav-pills moderation-category d-none d-md-flex w-100"
id="pills-tab"
role="tablist"
aria-label="Media galleries"
>
<li class="nav-item" role="presentation">
<button
class="nav-link active w-100 text-center"
id="pills-moderate-tab"
aria-label="Moderate Media Gallery"
data-bs-toggle="pill"
data-bs-target="#pills-moderate"
type="button"
role="tab"
aria-controls="pills-moderate"
aria-selected="true"
tabindex="-1"
>
<span class="wu-tab-label" data-tab-label>Moderate Media Gallery</span>
<span class="wu-tab-short" aria-hidden="true">Moderation</span>
<span class="badge wu-badge wu-badge--primary-fill" data-tab-count>24</span>
</button>
</li>
<li class="nav-item" role="presentation">
<button
class="nav-link w-100 text-center"
id="pills-guestbook-tab"
aria-label="Guestbook Media Gallery"
data-bs-toggle="pill"
data-bs-target="#pills-guestbook"
type="button"
role="tab"
aria-controls="pills-guestbook"
aria-selected="false"
tabindex="-1"
>
<span class="wu-tab-label" data-tab-label>Guestbook Media Gallery</span>
<span class="wu-tab-short" aria-hidden="true">Guestbook</span>
<span class="badge wu-badge wu-badge--primary-fill" data-tab-count>56</span>
</button>
</li>
<li class="nav-item" role="presentation">
<button
class="nav-link w-100 text-center"
id="pills-voicemail-tab"
aria-label="Voicemail Media Gallery"
data-bs-toggle="pill"
data-bs-target="#pills-voicemail"
type="button"
role="tab"
aria-controls="pills-voicemail"
aria-selected="false"
>
<span class="wu-tab-label" data-tab-label>Voicemail Media Gallery</span>
<span class="wu-tab-short" aria-hidden="true">Voicemail</span>
<span class="badge wu-badge wu-badge--primary-fill" data-tab-count>127</span>
</button>
</li>
<li class="nav-item" role="presentation">
<button
class="nav-link w-100 text-center"
id="pills-reinstate-tab"
aria-label="Hidden Media Gallery"
data-bs-toggle="pill"
data-bs-target="#pills-reinstate"
type="button"
role="tab"
aria-controls="pills-reinstate"
aria-selected="false"
tabindex="-1"
>
<span class="wu-tab-label" data-tab-label>Hidden Media Gallery</span>
<span class="wu-tab-short" aria-hidden="true">Hidden Media</span>
<span class="badge wu-badge wu-badge--primary-fill" data-tab-count>10</span>
</button>
</li>
</ul>
<div class="dropdown wu-tab-select d-md-none w-100">
<button
class="wu-tab-select-trigger"
id="moderationGallerySelect"
type="button"
data-bs-toggle="dropdown"
data-bs-offset="0,8"
aria-expanded="false"
aria-controls="moderationGalleryMenu"
>
<span class="visually-hidden">Choose gallery:</span>
<span class="wu-tab-selected-label" data-selected-label>Moderate Media Gallery</span>
<span class="badge wu-badge wu-badge--primary-fill" data-selected-count>24</span>
<span class="wu-locale-chevron" aria-hidden="true"></span>
</button>
<ul class="dropdown-menu" id="moderationGalleryMenu" aria-labelledby="moderationGallerySelect">
<li>
<button class="dropdown-item active" type="button" data-tab-trigger="pills-moderate-tab">
<span>Moderate Media Gallery</span>
<span class="badge wu-badge wu-badge--primary-fill" data-option-count>24</span>
</button>
</li>
<li>
<button class="dropdown-item" type="button" data-tab-trigger="pills-guestbook-tab">
<span>Guestbook Media Gallery</span>
<span class="badge wu-badge wu-badge--primary-fill" data-option-count>56</span>
</button>
</li>
<li>
<button class="dropdown-item" type="button" data-tab-trigger="pills-voicemail-tab">
<span>Voicemail Media Gallery</span>
<span class="badge wu-badge wu-badge--primary-fill" data-option-count>127</span>
</button>
</li>
<li>
<button class="dropdown-item" type="button" data-tab-trigger="pills-reinstate-tab">
<span>Hidden Media Gallery</span>
<span class="badge wu-badge wu-badge--primary-fill" data-option-count>10</span>
</button>
</li>
</ul>
</div>
</div>
<div class="tab-content" id="pills-tabContent">
<div
class="tab-pane fade show active"
id="pills-moderate"
role="tabpanel"
aria-labelledby="pills-moderate-tab"
tabindex="0"
>
<p class="mb-0 p-3">Moderate Media Gallery content</p>
</div>
<div
class="tab-pane fade"
id="pills-guestbook"
role="tabpanel"
aria-labelledby="pills-guestbook-tab"
tabindex="0"
>
<p class="mb-0 p-3">Guestbook Media Gallery content</p>
</div>
<div
class="tab-pane fade"
id="pills-voicemail"
role="tabpanel"
aria-labelledby="pills-voicemail-tab"
tabindex="0"
>
<p class="mb-0 p-3">Voicemail Media Gallery content</p>
</div>
<div
class="tab-pane fade"
id="pills-reinstate"
role="tabpanel"
aria-labelledby="pills-reinstate-tab"
tabindex="0"
>
<p class="mb-0 p-3">Hidden Media Gallery content</p>
</div>
</div>
CSS reference & dependencies
.wu-moderation-tabs.wu-tab-label.wu-tab-short.wu-badge.wu-badge--primary-fill.wu-tab-select.wu-tab-select-trigger.wu-tab-selected-label.wu-locale-chevron
Stylesheets · in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css
assets/css/wu-components.css
application/assets/css/application-shell.css
application/assets/css/application-features.css
public/assets/css/guest-album.css
application/assets/css/application-album.css
assets/css/wu-icons.css
Scripts · once, in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js
application/assets/js/moderation-tabs.js
Dependency paths below are relative to the project root. Source snippet asset paths are relative to application/. Adjust paths when moving a snippet.
Dependencies
Copy Dependencies
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link href="assets/css/wu-components.css" rel="stylesheet" />
<link href="application/assets/css/application-shell.css" rel="stylesheet" />
<link href="application/assets/css/application-features.css" rel="stylesheet" />
<link href="public/assets/css/guest-album.css" rel="stylesheet" />
<link href="application/assets/css/application-album.css" rel="stylesheet" />
<link href="assets/css/wu-icons.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
<script src="application/assets/js/moderation-tabs.js"></script>
Tab triggers/dropdown are source markup; heavy feature panels are reduced to labelled tab contents for this navigation example.
Actions dropdown
Source: application/dashboard.html · .wu-action-menu.dropdown
Bootstrap Dropdown owns open/close and aria-expanded. Preserve the fixed Popper configuration used by table menus.
The menu links open source pages. Feature modal targets require their corresponding source overlay blocks.
HTML example
HTML
Copy HTML
<div class="wu-action-menu dropdown">
<button
class="wu-button wu-button--outline wu-button-sm"
aria-expanded="false"
type="button"
data-bs-toggle="dropdown"
data-bs-config='{"popperConfig":{"strategy":"fixed"}}'
>
<i class="wu-icon wu-icon--setting-gold wu-icon--sm"></i>
Actions
</button>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<a type="button" class="dropdown-item" href="album.html" data-preserve-plan="">
<i class="wu-icon wu-icon--gallery wu-icon--sm"></i>
Manage album
</a>
</li>
<li>
<a
class="dropdown-item"
type="button"
data-modal-open="shareStudioModal"
data-bs-toggle="modal"
data-bs-target="#shareStudioModal"
aria-controls="shareStudioModalTitle"
>
<i class="wu-icon wu-icon--share wu-icon--sm"></i>
Guest Page
</a>
</li>
<li>
<a class="dropdown-item" href="moderation.html?tab=moderation">
<i class="wu-icon wu-icon--setting-gold wu-icon--sm"></i>
Moderate Album
</a>
</li>
<li>
<a class="dropdown-item" href="moderation.html?tab=reinstate">
<i class="wu-icon wu-icon--reinstate wu-icon--sm"></i>
Reinstate Photo
</a>
</li>
<hr class="my-1" />
<li>
<button
class="dropdown-item text-danger-500"
data-modal-open="wuDeleteConfirmation"
data-bs-toggle="modal"
data-bs-target="#wuDeleteConfirmation"
aria-controls="wuDeleteConfirmationTitle"
>
<i class="wu-icon wu-icon--trash wu-icon--sm"></i>
Delete album
</button>
</li>
</ul>
</div>
<!-- Related source overlay blocks required by these triggers. -->
<div
class="wu-modal modal fade"
id="shareStudioModal"
tabindex="-1"
aria-labelledby="shareStudioModalTitle"
aria-hidden="true"
>
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div class="wu-modal-card wu-modal-md modal-content">
<div class="wu-modal-head modal-header">
<h2 class="text-bronze-600 fw-bold" id="shareStudioModalTitle">Share Album Link</h2>
<button
class="btn-close"
data-modal-close=""
type="button"
data-bs-dismiss="modal"
aria-label="Close"
></button>
</div>
<div class="wu-modal-body modal-body">
<div class="wu-studio-grid d-flex align-items-center gap-4">
<img src="../public/assets/images/06-tools/qr-preview.svg" alt="" />
<div>
<h6 class="text-neutral-900 mb-1">Share it to your guest</h6>
<p class="mb-0 text-neutral-500">
Scan the QR code or send the album link. Guests do not need an account
</p>
</div>
</div>
<div class="d-flex align-items-center justify-content-between gap-2 mt-3 mb-0">
<div class="input-group">
<span class="input-group-text" aria-hidden="true">
<i class="wu-icon wu-icon--link wu-icon--sm"></i>
</span>
<input
class="form-control wu-input bg-neutral-0 text-truncate"
value="https://weduploader.com/upload/9Q7kessLV2yo4fLt"
readonly
/>
</div>
<button class="wu-button rounded-square wu-button--primary wu-button-sm">
<i class="wu-icon wu-icon--copy-light wu-icon--md"></i>
</button>
</div>
</div>
<div class="modal-footer justify-content-between">
<button class="wu-button" data-modal-close="" type="button" data-bs-dismiss="modal">
Close
</button>
<a
href="https://weduploader.com/upload/9Q7kessLV2yo4fLt"
target="_blank"
class="wu-button wu-button--primary-light"
type="button"
>
Go to Album
<i class="wu-icon wu-icon--arrow-right-white wu-icon--sm"></i>
</a>
</div>
</div>
</div>
</div>
<div
class="modal fade wu-modal wu-delete-modal"
id="wuDeleteConfirmation"
tabindex="-1"
aria-labelledby="wuDeleteConfirmationTitle"
aria-describedby="wuDeleteConfirmationDescription"
aria-hidden="true"
>
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-body p-4">
<div class="w-100 text-center py-4">
<i class="wu-icon wu-icon--warning-red wu-icon--super"></i>
</div>
<h5 id="wuDeleteConfirmationTitle" class="mb-1 text-center">
Delete Albums
<strong>Emma & Liam?</strong>
</h5>
<p id="wuDeleteConfirmationDescription" class="text-center text-neutral-500">
You cannot undo deletions. Are you sure you want to delete this WedUploader album?
</p>
<div class="wu-logout-actions mt-3">
<button type="button" class="wu-button" data-bs-dismiss="modal">Cancel</button>
<a
class="wu-button wu-button--danger"
data-logout-confirm
href="dashboard.html"
data-preserve-plan=""
>
Yes, Delete.
</a>
</div>
</div>
</div>
</div>
</div>
CSS reference & dependencies
.wu-action-menu.wu-button.wu-button--outline.wu-button-sm.wu-icon.wu-icon--setting-gold.wu-icon--sm.wu-icon--gallery.wu-icon--share.wu-icon--reinstate.wu-icon--trash
Stylesheets · in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css
assets/css/wu-icons.css
assets/css/wu-components.css
assets/css/wu-form-controls.css
application/assets/css/application-shell.css
application/assets/css/application-features.css
Scripts · once, in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js
Dependency paths below are relative to the project root. Source snippet asset paths are relative to application/. Adjust paths when moving a snippet.
Dependencies
Copy Dependencies
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link href="assets/css/wu-icons.css" rel="stylesheet" />
<link href="assets/css/wu-components.css" rel="stylesheet" />
<link href="assets/css/wu-form-controls.css" rel="stylesheet" />
<link href="application/assets/css/application-shell.css" rel="stylesheet" />
<link href="application/assets/css/application-features.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
Source excerpt; no component class renaming.
Application breadcrumb
Source: application/dashboard.html · .wu-breadcrumb
Keep the breadcrumb in .wu-top-left inside .wu-topbar when composing a full Application page.
HTML example
HTML
Copy HTML
<div aria-label="Breadcrumb" class="wu-breadcrumb">
<span class="wu-breadcrumb-home">
<i class="wu-icon wu-icon--home wu-icon--xs"></i>
</span>
<span>Home</span>
<span>›</span>
<strong>Dashboard</strong>
</div>
CSS reference & dependencies
.wu-breadcrumb.wu-breadcrumb-home.wu-icon.wu-icon--home.wu-icon--xs
Stylesheets · in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css
assets/css/wu-icons.css
assets/css/wu-components.css
assets/css/wu-form-controls.css
application/assets/css/application-shell.css
application/assets/css/application-features.css
Scripts · once, in this order
No component JavaScript required.
Dependency paths below are relative to the project root. Source snippet asset paths are relative to application/. Adjust paths when moving a snippet.
Dependencies
Copy Dependencies
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link href="assets/css/wu-icons.css" rel="stylesheet" />
<link href="assets/css/wu-components.css" rel="stylesheet" />
<link href="assets/css/wu-form-controls.css" rel="stylesheet" />
<link href="application/assets/css/application-shell.css" rel="stylesheet" />
<link href="application/assets/css/application-features.css" rel="stylesheet" />
Source excerpt; no component class renaming.
Use the card family for its original context. Public feature/editorial cards and Application setting panels have different CSS dependencies.
Public feature card
Source: public/index.html · .wu-latest-feature-card
Use the original Public page stylesheet stack. These are Public components, not generic Application .wu-card variants.
AOS metadata is retained in the copied markup; animation is paused in the isolated preview so content remains visible.
HTML example
HTML
Copy HTML
<article class="wu-latest-feature-card" data-aos="fade-down" data-aos-duration="700">
<div class="wu-tile-icon">
<img class="text-gold-500" src="../assets/icons/user.svg" alt="" />
</div>
<h3 class="fw-bold">No app. No guest account.</h3>
<p>Guest open your URL or scan the QR Code and upload from the browser they already use.</p>
</article>
CSS reference & dependencies
.wu-latest-feature-card.wu-tile-icon
Stylesheets · in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css
public/assets/css/components.css
public/assets/css/public.css
public/assets/css/homepage.css
public/assets/css/site-shell.css
public/assets/css/responsive.css
assets/css/wu-icons.css
Scripts · once, in this order
No component JavaScript required.
Dependency paths below are relative to the project root. Source snippet asset paths are relative to public/. Adjust paths when moving a snippet.
Dependencies
Copy Dependencies
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link href="public/assets/css/components.css" rel="stylesheet" />
<link href="public/assets/css/public.css" rel="stylesheet" />
<link href="public/assets/css/homepage.css" rel="stylesheet" />
<link href="public/assets/css/site-shell.css" rel="stylesheet" />
<link href="public/assets/css/responsive.css" rel="stylesheet" />
<link href="assets/css/wu-icons.css" rel="stylesheet" />
Source card; editorial card retains its original .wu-learn-grid parent with one item for realistic sizing.
Review card
Source: public/index.html · .wu-review-card
Use the original Public page stylesheet stack. These are Public components, not generic Application .wu-card variants.
AOS metadata is retained in the copied markup; animation is paused in the isolated preview so content remains visible.
HTML example
HTML
Copy HTML
<article class="wu-review-card" data-aos="zoom-in-up" data-aos-delay="300" data-aos-duration="700">
<blockquote>
“WedUploader was easy to use plus I didn’t have to track down all the pictures that my friends
and family took at my wedding.”
</blockquote>
<div class="wu-review-meta">
<div>
<strong>Gill R.</strong>
<span class="wu-review-stars" aria-label="5 out of 5 stars">★★★★★</span>
</div>
<span>Customer</span>
</div>
</article>
CSS reference & dependencies
.wu-review-card.wu-review-meta.wu-review-stars
Stylesheets · in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css
public/assets/css/components.css
public/assets/css/public.css
public/assets/css/homepage.css
public/assets/css/site-shell.css
public/assets/css/responsive.css
assets/css/wu-icons.css
Scripts · once, in this order
No component JavaScript required.
Dependency paths below are relative to the project root. Source snippet asset paths are relative to public/. Adjust paths when moving a snippet.
Dependencies
Copy Dependencies
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link href="public/assets/css/components.css" rel="stylesheet" />
<link href="public/assets/css/public.css" rel="stylesheet" />
<link href="public/assets/css/homepage.css" rel="stylesheet" />
<link href="public/assets/css/site-shell.css" rel="stylesheet" />
<link href="public/assets/css/responsive.css" rel="stylesheet" />
<link href="assets/css/wu-icons.css" rel="stylesheet" />
Source card; editorial card retains its original .wu-learn-grid parent with one item for realistic sizing.
Editorial media card
Source: public/index.html · .wu-story-card
Use the original Public page stylesheet stack. These are Public components, not generic Application .wu-card variants.
AOS metadata is retained in the copied markup; animation is paused in the isolated preview so content remains visible.
HTML example
HTML
Copy HTML
<div class="wu-learn-grid">
<article
class="wu-story-card wu-story-card--featured"
data-aos="zoom-out-left"
data-aos-delay="300"
data-aos-duration="700"
>
<div class="wu-story-card-media wu-photo">
<img
alt="Wedding party gathered together"
decoding="async"
height="650"
loading="lazy"
src="assets/images/memory-01.webp"
width="960"
/>
</div>
<div class="wu-story-card-copy">
<span class="wu-kicker">Tutorial</span>
<h2 class="wu-font-display">How to collect wedding photos from your guests</h2>
<p class="my-3 text-neutral-500">
No tier maze the redesign makes one time premium propositions
</p>
<a class="wu-text-link dark" href="tutorials.html">Read tutorial →</a>
</div>
</article>
</div>
CSS reference & dependencies
.wu-learn-grid.wu-story-card.wu-story-card-media.wu-photo.wu-story-card-copy.wu-kicker.wu-font-display.wu-text-link
Stylesheets · in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css
public/assets/css/components.css
public/assets/css/public.css
public/assets/css/homepage.css
public/assets/css/site-shell.css
public/assets/css/responsive.css
assets/css/wu-icons.css
Scripts · once, in this order
No component JavaScript required.
Dependency paths below are relative to the project root. Source snippet asset paths are relative to public/. Adjust paths when moving a snippet.
Dependencies
Copy Dependencies
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link href="public/assets/css/components.css" rel="stylesheet" />
<link href="public/assets/css/public.css" rel="stylesheet" />
<link href="public/assets/css/homepage.css" rel="stylesheet" />
<link href="public/assets/css/site-shell.css" rel="stylesheet" />
<link href="public/assets/css/responsive.css" rel="stylesheet" />
<link href="assets/css/wu-icons.css" rel="stylesheet" />
Source card; editorial card retains its original .wu-learn-grid parent with one item for realistic sizing.
Album identity panel
Source: application/album.html · .wu-card.wu-album-identity-panel
This editable panel belongs to Application album settings. The inputs are native; app-specific synchronization requires album-inline.js on the complete page.
HTML example
HTML
Copy HTML
<div aria-label="Album details" class="wu-card wu-album-identity-panel" data-tour-target="identity">
<div class="wu-inline-section-intro">
<span>
<i class="wu-icon wu-icon--folder-combine wu-icon--xxxl"></i>
</span>
<div>
<span data-album-name="">
Drive Folder:
<a href="" class="text-decoration-underline">emma-liam</a>
</span>
<small id="albumContextMeta" class="fw-normal text-neutral-500">Aug 24, 2026</small>
</div>
</div>
<div class="wu-album-identity-fields">
<div>
<label for="albumTitle" class="form-label wu-label text-gold-800 mb-1">Album title</label>
<input
id="albumTitle"
class="form-control form-control-sm wu-input"
name="title"
value="Emma & Liam Wedding"
/>
</div>
<div>
<label for="inlineAlbumFolder" class="form-label wu-label text-gold-800 mb-1">
Folder Name
</label>
<input
id="inlineAlbumFolder"
class="form-control form-control-sm wu-input"
name="folder"
value="emma-liam"
/>
</div>
<div>
<label for="inlineAlbumDate" class="form-label wu-label text-gold-800 mb-1">Event Date</label>
<input
id="inlineAlbumDate"
class="form-control form-control-sm wu-input"
name="date"
type="date"
value="2026-08-24"
/>
</div>
</div>
</div>
CSS reference & dependencies
.wu-card.wu-album-identity-panel.wu-inline-section-intro.wu-icon.wu-icon--folder-combine.wu-icon--xxxl.wu-album-identity-fields.wu-label.wu-input
Stylesheets · in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css
assets/css/wu-components.css
application/assets/css/application-shell.css
assets/css/wu-form-controls.css
application/assets/css/application-features.css
application/assets/css/application-album.css
assets/css/wu-icons.css
Scripts · once, in this order
No component JavaScript required.
Dependency paths below are relative to the project root. Source snippet asset paths are relative to application/. Adjust paths when moving a snippet.
Dependencies
Copy Dependencies
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link href="assets/css/wu-components.css" rel="stylesheet" />
<link href="application/assets/css/application-shell.css" rel="stylesheet" />
<link href="assets/css/wu-form-controls.css" rel="stylesheet" />
<link href="application/assets/css/application-features.css" rel="stylesheet" />
<link href="application/assets/css/application-album.css" rel="stylesheet" />
<link href="assets/css/wu-icons.css" rel="stylesheet" />
Source excerpt; no component class renaming.
Dashboard empty state
Source: application/dashboard.html · #dashboardEmpty
The empty component is static HTML. entitlements.js chooses the empty/free/premium wrapper on the full dashboard.
Preview opens the actual Create Album modal; submitting is paused in documentation because application.js owns the demo creation/redirect.
HTML example
HTML
Copy HTML
<div class="wu-empty" id="dashboardEmpty">
<div class="p-3 p-sm-0">
<div aria-hidden="true" class="wu-empty-mark mb-4">
<i class="wu-icon wu-icon--folder-combine wu-icon--lg"></i>
</div>
<h6 id="dashboardEmptyTitle" class="mb-1 text-neutral-900 fw-bold">No Albums yet</h6>
<p id="dashboardEmptyCopy" class="text-neutral-500">
Create your album and start sharing your happiness
</p>
<button
class="wu-button wu-button--primary"
data-modal-open="createAlbumModal"
data-bs-toggle="modal"
data-bs-target="#createAlbumModal"
aria-controls="createAlbumModal"
>
<i class="wu-icon wu-icon--plus-white wu-icon--sm" aria-hidden="true"></i>
Add New Album
</button>
</div>
</div>
<!-- Related source overlay blocks required by these triggers. -->
<div
class="wu-modal modal fade"
id="createAlbumModal"
tabindex="-1"
aria-labelledby="createAlbumModalTitle"
aria-hidden="true"
>
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div class="wu-modal-card modal-content">
<form id="createAlbumForm">
<div class="wu-modal-head modal-header">
<h2 class="text-bronze-600 fw-bold" id="createAlbumModalTitle">Create Album</h2>
<button
class="btn-close"
data-modal-close=""
type="button"
data-bs-dismiss="modal"
aria-label="Close"
></button>
</div>
<div class="wu-modal-body modal-body">
<div class="mb-3">
<label for="eventTitle" class="form-label wu-label">
<span class="text-danger-500">*</span>
Event title
</label>
<input
id="eventTitle"
class="form-control wu-input"
name="title"
placeholder="Emma & Liam Wedding"
required
/>
</div>
<div class="mb-3">
<label for="folderName" class="form-label wu-label">
<span class="text-danger-500">*</span>
Drive folder name
</label>
<input
id="folderName"
class="form-control wu-input"
name="folder"
placeholder="Example: emma-liam"
required
/>
</div>
<div class="mb-3">
<label for="eventDate" class="form-label wu-label">
<span class="text-danger-500">*</span>
Event Date
</label>
<input
id="eventDate"
class="form-control wu-input"
name="date"
placeholder="DD / MM / YY"
required
type="date"
/>
</div>
<div class="mb-3">
<label class="form-label wu-label">Gallery visibility</label>
<div class="form-check form-switch wu-form-switch">
<input
class="form-check-input"
type="checkbox"
role="switch"
id="largeSwitch"
name="public"
checked
aria-describedby="largeSwitchHelp"
/>
<label class="form-check-label" for="largeSwitch">Public</label>
<small class="wu-form-switch-help" id="largeSwitchHelp">
Uploaded photos will be visible to guests.
</small>
</div>
</div>
</div>
<div class="wu-modal-foot justify-content-between modal-footer">
<button
class="wu-button wu-button-md wu-button--outline"
data-modal-close=""
type="button"
data-bs-dismiss="modal"
>
Cancel
</button>
<button
class="wu-button wu-button-md wu-button--primary"
data-modal-open="loadingModal"
data-bs-toggle="modal"
data-bs-target="#loadingModal"
aria-controls="loadingModalTitle"
>
Create Album
</button>
</div>
</form>
</div>
</div>
</div>
<div
class="wu-modal modal fade"
id="loadingModal"
tabindex="-1"
aria-labelledby="loadingModalTitle"
aria-describedby="loadingModalDescription"
aria-hidden="true"
data-bs-backdrop="static"
data-bs-keyboard="false"
>
<div class="modal-dialog modal-dialog-centered">
<div class="wu-modal-card modal-content">
<div class="wu-modal-body modal-body text-center" role="status" aria-live="polite">
<div data-album-submit-animation aria-hidden="true">
<div class="preloader-img">
<img src="../assets/logo/apple-touch-icon-01.png" alt="" />
</div>
</div>
<h6 id="createAlbumLoadingTitle" class="mb-1 fw-bold">Processing</h6>
<p id="createAlbumLoadingDescription" class="mb-0 text-neutral-500">Please Wait</p>
</div>
</div>
</div>
</div>
CSS reference & dependencies
.wu-empty.wu-empty-mark.wu-icon.wu-icon--folder-combine.wu-icon--lg.wu-button.wu-button--primary.wu-icon--plus-white.wu-icon--sm
Stylesheets · in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css
assets/css/wu-icons.css
assets/css/wu-components.css
assets/css/wu-form-controls.css
application/assets/css/application-shell.css
application/assets/css/application-features.css
Scripts · once, in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js
Dependency paths below are relative to the project root. Source snippet asset paths are relative to application/. Adjust paths when moving a snippet.
Dependencies
Copy Dependencies
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link href="assets/css/wu-icons.css" rel="stylesheet" />
<link href="assets/css/wu-components.css" rel="stylesheet" />
<link href="assets/css/wu-form-controls.css" rel="stylesheet" />
<link href="application/assets/css/application-shell.css" rel="stylesheet" />
<link href="application/assets/css/application-features.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
Source excerpt; no component class renaming.
Source clarification. The current ZIP contains native details/summary FAQ accordions. It contains no Bootstrap Collapse accordion in Public/Application HTML. The working source pattern is documented below; a new accordion library has not been introduced.
FAQ accordion — native details
Source: public/index.html · .wu-faq-list > details > summary + .wu-faq-answer
The current implementation uses native details/summary. No Bootstrap Collapse markup exists in the Public/Application HTML in this ZIP.
Open/close works without JavaScript. Preserve the open attribute only for the item intended to start expanded.
Two existing FAQ items are shown. The pattern allows independent open items.
HTML example
HTML
Copy HTML
<div class="wu-faq-list" data-aos="fade-left" data-aos-delay="300" data-aos-duration="700">
<details open>
<summary>Is WedUploader really free for guests?</summary>
<div class="wu-faq-answer">
Yes. Guests can upload through the album link or QR code without purchasing anything or
creating an account.
</div>
</details>
<details>
<summary>How do I share my unique WedUploader website with my guests?</summary>
<div class="wu-faq-answer">
Share your album link or its QR code so guests can open the album in their browser.
</div>
</details>
</div>
CSS reference & dependencies
.wu-faq-list.wu-faq-answer
Stylesheets · in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css
public/assets/css/components.css
public/assets/css/public.css
public/assets/css/homepage.css
public/assets/css/site-shell.css
public/assets/css/responsive.css
assets/css/wu-icons.css
Scripts · once, in this order
No component JavaScript required.
Dependency paths below are relative to the project root. Source snippet asset paths are relative to public/. Adjust paths when moving a snippet.
Dependencies
Copy Dependencies
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link href="public/assets/css/components.css" rel="stylesheet" />
<link href="public/assets/css/public.css" rel="stylesheet" />
<link href="public/assets/css/homepage.css" rel="stylesheet" />
<link href="public/assets/css/site-shell.css" rel="stylesheet" />
<link href="public/assets/css/responsive.css" rel="stylesheet" />
<link href="assets/css/wu-icons.css" rel="stylesheet" />
First two source FAQ items; native interaction unchanged.
Bootstrap owns modal/offcanvas visibility, backdrop, transitions, scroll lock and focus. Keep the corresponding source trigger and overlay markup together. Full Application feature scripts are not loaded into generic documentation examples.
Guest information dialog
Source: public/guest-template-1.html · [data-bs-target="#helpDialog"] + #helpDialog
Bootstrap Modal owns backdrop, scrolling, Escape and focus. Keep trigger data-bs-target and modal ID in sync.
This is the Guest Album dialog appearance; Application .wu-modal has a different content anatomy.
HTML example
HTML
Copy HTML
<button
type="button"
class="wu-button wu-button-md wu-button--outline"
data-dialog-open="helpDialog"
data-bs-toggle="modal"
data-bs-target="#helpDialog"
>
View 3-step guide
<i class="wu-icon wu-icon--search-gold wu-icon--sm" aria-hidden="true"></i>
</button>
<div
class="modal fade wu-guest-dialog"
id="helpDialog"
tabindex="-1"
aria-labelledby="helpDialogTitle"
aria-hidden="true"
>
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header">
<div>
<p class="wu-guest-eyebrow text-gold-500 mb-0">View 3-step guide</p>
<h2 id="helpDialogTitle" class="wu-font-display">Upload in three steps</h2>
</div>
<button
type="button"
class="btn-close"
data-dialog-close
aria-label="Close"
data-bs-dismiss="modal"
></button>
</div>
<div class="modal-body">
<ol class="wu-guest-steps mb-4">
<li>
<span class="wu-font-display count">1</span>
<div class="text-instruction">
<strong>Choose files</strong>
<p class="mb-0">
Select photos or videos from your device. You can add more before sending.
</p>
</div>
<span class="icon p-3 bg-gold-100 align-self-center rounded-circle">
<i class="wu-icon wu-icon--gallery wu-icon-md"></i>
</span>
</li>
<li>
<span class="wu-font-display count">2</span>
<div class="text-instruction">
<strong>Review your files</strong>
<p class="mb-0">
Check the selection and optionally leave a message or record a voicemail.
</p>
</div>
<span class="icon p-3 bg-gold-100 align-self-center rounded-circle">
<i class="wu-icon wu-icon--folder wu-icon-md"></i>
</span>
</li>
<li>
<span class="wu-font-display count">3</span>
<div class="text-instruction">
<strong>Start upload</strong>
<p class="mb-0">Keep this page open until every file has finished.</p>
</div>
<span class="icon p-3 bg-gold-100 align-self-center rounded-circle">
<i class="wu-icon wu-icon--cloud-upload wu-icon-md"></i>
</span>
</li>
</ol>
<div class="wu-guest-note wu-alert wu-alert--warning rounded">
<img src="../assets/icons/warning-alert.svg" />
<span class="fw-bold">Please remain on this page until all uploads complete.</span>
</div>
</div>
</div>
</div>
</div>
CSS reference & dependencies
.wu-button.wu-button-md.wu-button--outline.wu-icon.wu-icon--search-gold.wu-icon--sm.wu-guest-dialog.wu-guest-eyebrow.wu-font-display.wu-guest-steps.wu-icon--gallery
Stylesheets · in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css
assets/css/wu-foundation.css
assets/css/wu-components.css
assets/css/wu-icons.css
public/assets/css/public.css
public/assets/css/guest-album.css
Scripts · once, in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js
Dependency paths below are relative to the project root. Source snippet asset paths are relative to public/. Adjust paths when moving a snippet.
Dependencies
Copy Dependencies
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link href="assets/css/wu-foundation.css" rel="stylesheet" />
<link href="assets/css/wu-components.css" rel="stylesheet" />
<link href="assets/css/wu-icons.css" rel="stylesheet" />
<link href="public/assets/css/public.css" rel="stylesheet" />
<link href="public/assets/css/guest-album.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
Source excerpt; no component class renaming.
Application confirmation dialog
Source: application/dashboard.html · #wuDeleteConfirmation
The dialog pattern is source markup; it does not perform a backend delete.
Do not attach an extra overlay lifecycle handler. Bootstrap owns display/focus; the actual feature controller owns confirmation processing.
HTML example
HTML
Copy HTML
<button
class="dropdown-item text-danger-500"
data-modal-open="wuDeleteConfirmation"
data-bs-toggle="modal"
data-bs-target="#wuDeleteConfirmation"
aria-controls="wuDeleteConfirmationTitle"
>
<i class="wu-icon wu-icon--trash wu-icon--sm"></i>
Delete album
</button>
<div
class="modal fade wu-modal wu-delete-modal"
id="wuDeleteConfirmation"
tabindex="-1"
aria-labelledby="wuDeleteConfirmationTitle"
aria-describedby="wuDeleteConfirmationDescription"
aria-hidden="true"
>
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-body p-4">
<div class="w-100 text-center py-4">
<i class="wu-icon wu-icon--warning-red wu-icon--super"></i>
</div>
<h5 id="wuDeleteConfirmationTitle" class="mb-1 text-center">
Delete Albums
<strong>Emma & Liam?</strong>
</h5>
<p id="wuDeleteConfirmationDescription" class="text-center text-neutral-500">
You cannot undo deletions. Are you sure you want to delete this WedUploader album?
</p>
<div class="wu-logout-actions mt-3">
<button type="button" class="wu-button" data-bs-dismiss="modal">Cancel</button>
<a
class="wu-button wu-button--danger"
data-logout-confirm
href="dashboard.html"
data-preserve-plan=""
>
Yes, Delete.
</a>
</div>
</div>
</div>
</div>
</div>
CSS reference & dependencies
.wu-icon.wu-icon--trash.wu-icon--sm.wu-modal.wu-icon--warning-red.wu-icon--super.wu-logout-actions.wu-button.wu-button--danger
Stylesheets · in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css
assets/css/wu-icons.css
assets/css/wu-components.css
assets/css/wu-form-controls.css
application/assets/css/application-shell.css
application/assets/css/application-features.css
Scripts · once, in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js
Dependency paths below are relative to the project root. Source snippet asset paths are relative to application/. Adjust paths when moving a snippet.
Dependencies
Copy Dependencies
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link href="assets/css/wu-icons.css" rel="stylesheet" />
<link href="assets/css/wu-components.css" rel="stylesheet" />
<link href="assets/css/wu-form-controls.css" rel="stylesheet" />
<link href="application/assets/css/application-shell.css" rel="stylesheet" />
<link href="application/assets/css/application-features.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
Source excerpt; no component class renaming.
Settings offcanvas
Source: application/dashboard.html · [data-bs-target="#settingsDrawer"] + #settingsDrawer
Use Bootstrap Offcanvas data-bs-toggle/data-bs-dismiss. It is not the Public hamburger menu.
In a full Application page load application-shell.js and application.js once, in source order. This isolated drawer needs Bootstrap only for opening/closing.
HTML example
HTML
Copy HTML
<a
class="wu-profile-item"
data-bs-toggle="offcanvas"
data-bs-target="#settingsDrawer"
aria-controls="settingsDrawer"
>
<i class="wu-icon wu-icon--setting wu-icon--sm"></i>
Settings
</a>
<div
class="offcanvas offcanvas-end wu-drawer wu-settings-drawer"
tabindex="-1"
id="settingsDrawer"
aria-labelledby="settingsDrawerTitle"
>
<div class="offcanvas-header">
<h2 class="offcanvas-title" id="settingsDrawerTitle">Settings</h2>
<button
type="button"
class="btn-close"
data-bs-dismiss="offcanvas"
aria-label="Close Settings"
></button>
</div>
<div class="offcanvas-body">
<div class="wu-drawer-profile">
<div class="wu-drawer-avatar" aria-hidden="true">DM</div>
<h3>Derick Metzger</h3>
</div>
<div class="wu-settings-sections">
<div class="wu-setting-block wu-setting-notification">
<label for="settingsEmailNotification">Email notification</label>
<div class="form-check form-switch">
<input
class="form-check-input"
type="checkbox"
role="switch"
id="settingsEmailNotification"
aria-describedby="settingsNotificationState"
/>
<span class="form-check-label" id="settingsNotificationState">Off</span>
</div>
</div>
<div class="wu-setting-block">
<h3 class="wu-setting-title justify-content-start">Event Manager</h3>
<p class="wu-help mb-0" id="eventManagerHelp">
Event managers can help manage WedUploader albums and account actions. Google Drive access
is not automatically granted. You may have up to
<strong>2 email addresses</strong>
, per account, active at any given time.
</p>
<label class="visually-hidden" for="eventManagerEmail">Event manager email address</label>
<input
class="wu-input"
id="eventManagerEmail"
type="email"
placeholder="Email Address"
aria-describedby="eventManagerHelp"
/>
<div class="wu-settings-add">
<button class="wu-button wu-button--ghost" type="button" data-toast="Event manager added">
<i class="wu-icon wu-icon--plus wu-icon--sm" aria-hidden="true"></i>
Add Email Address (1 Left)
</button>
</div>
</div>
<div class="wu-setting-block">
<h3 class="wu-setting-title justify-content-start">Transfer Account</h3>
<p class="wu-help mb-0">
The existing transfer flow moves the WedUploader account to a new email address. The
receiving account must accept the transfer and Google Drive permission.
</p>
<button
class="wu-button wu-button--danger wu-settings-transfer"
type="button"
data-toast="Transfer flow opened"
>
Transfer your Account
<i class="wu-icon wu-icon--cloud-share wu-icon--sm" aria-hidden="true"></i>
</button>
</div>
</div>
</div>
</div>
CSS reference & dependencies
.wu-profile-item.wu-icon.wu-icon--setting.wu-icon--sm.wu-drawer.wu-settings-drawer.wu-drawer-profile.wu-drawer-avatar.wu-settings-sections.wu-setting-block.wu-setting-notification.wu-setting-title
Stylesheets · in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css
assets/css/wu-icons.css
assets/css/wu-components.css
assets/css/wu-form-controls.css
application/assets/css/application-shell.css
application/assets/css/application-features.css
Scripts · once, in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js
Dependency paths below are relative to the project root. Source snippet asset paths are relative to application/. Adjust paths when moving a snippet.
Dependencies
Copy Dependencies
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link href="assets/css/wu-icons.css" rel="stylesheet" />
<link href="assets/css/wu-components.css" rel="stylesheet" />
<link href="assets/css/wu-form-controls.css" rel="stylesheet" />
<link href="application/assets/css/application-shell.css" rel="stylesheet" />
<link href="application/assets/css/application-features.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
Source excerpt; no component class renaming.
The Guest Album grid and the Application voicemail player are distinct media components. Their limitations are documented alongside the live controls.
Gallery grid, filter, sort & preview
Source: public/guest-template-1.html · [data-gallery-filter] / [data-gallery-sort] / [data-gallery] / #lightboxDialog
The grid uses original WebP assets with intrinsic dimensions, loading="lazy" and decoding="async".
guest-album.js owns filtering, sorting and lightbox navigation. The video state is currently a poster preview; this ZIP does not implement real video playback in that dialog.
Three source figures are included, preserving the photo/video data hooks.
HTML example
HTML
Copy HTML
<div
class="wu-guest-gallery-controls d-flex flex-column flex-sm-row align-items-end justify-content-between"
>
<div class="wu-field d-flex flex-column align-items-center justify-content-center">
<label class="form-label wu-guest-sort">Sort from</label>
<select class="form-select" data-gallery-sort aria-label="Sort gallery">
<option value="newest">Newest</option>
<option value="oldest">Oldest</option>
</select>
</div>
<div class="wu-segment-control" role="group" aria-label="Filter media">
<button type="button" class="is-active" aria-pressed="true" data-gallery-filter="all">
All Files
</button>
<button type="button" aria-pressed="false" data-gallery-filter="photo">Photos</button>
<button type="button" aria-pressed="false" data-gallery-filter="video">Videos</button>
</div>
</div>
<div class="wu-guest-gallery-grid" data-gallery>
<figure
class="wu-guest-media"
data-media-id="memory-01"
data-media-type="photo"
data-time="8"
data-photo-name="IMG_2301.jpg"
>
<img
src="assets/images/memory-01.webp"
width="960"
height="645"
loading="lazy"
decoding="async"
alt="Friends sharing a wedding selfie"
/>
<figcaption class="wu-guest-media__caption">IMG_2301.jpg</figcaption>
<div class="wu-guest-media__actions">
<button
type="button"
class="wu-button wu-button-sm wu-button--primary-light"
data-preview-photo=""
data-bs-toggle="modal"
data-bs-target="#lightboxDialog"
aria-label="View IMG_2301.jpg"
>
<i class="wu-icon wu-icon--magnifier-white wu-icon--sm" aria-hidden="true"></i>
</button>
</div>
</figure>
<figure
class="wu-guest-media"
data-media-id="memory-02"
data-media-type="photo"
data-time="7"
data-photo-name="IMG_2302.jpg"
>
<img
src="assets/images/memory-02.webp"
width="478"
height="698"
loading="lazy"
decoding="async"
alt="Guests celebrating with the couple"
/>
<figcaption class="wu-guest-media__caption">IMG_2302.jpg</figcaption>
<div class="wu-guest-media__actions">
<button
type="button"
class="wu-button wu-button-sm wu-button--primary-light"
data-preview-photo=""
data-bs-toggle="modal"
data-bs-target="#lightboxDialog"
aria-label="View IMG_2302.jpg"
>
<i class="wu-icon wu-icon--magnifier-white wu-icon--sm" aria-hidden="true"></i>
</button>
</div>
</figure>
<figure
class="wu-guest-media"
data-media-id="memory-07"
data-media-type="video"
data-time="2"
data-photo-name="VID_2307.mp4"
>
<img
src="assets/images/memory-07.webp"
width="717"
height="783"
loading="lazy"
decoding="async"
alt="Guests photographing Sophia and Ethan"
/>
<figcaption class="wu-guest-media__caption">VID_2307.mp4</figcaption>
<span class="wu-guest-media__badge" aria-hidden="true">▶ Video preview</span>
<div class="wu-guest-media__actions">
<button
type="button"
class="wu-button wu-button-sm wu-button--primary-light"
data-preview-photo=""
data-bs-toggle="modal"
data-bs-target="#lightboxDialog"
aria-label="View poster for VID_2307.mp4"
>
<i class="wu-icon wu-icon--magnifier-white wu-icon--sm" aria-hidden="true"></i>
</button>
</div>
</figure>
</div>
<div
class="modal fade wu-guest-dialog"
id="lightboxDialog"
tabindex="-1"
aria-labelledby="lightboxDialogTitle"
aria-hidden="true"
>
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable modal-lg">
<div class="modal-content">
<div class="modal-header">
<div>
<p class="wu-guest-eyebrow text-gold-500 mb-0">Guest gallery</p>
<h2 id="lightboxDialogTitle" class="wu-font-display">Photo preview</h2>
</div>
<button
type="button"
class="btn-close"
data-dialog-close
aria-label="Close"
data-bs-dismiss="modal"
></button>
</div>
<div class="modal-body">
<div class="wu-guest-lightbox">
<img data-lightbox-image alt="Selected wedding media" />
<div class="wu-guest-lightbox__nav" aria-label="Gallery navigation">
<button
type="button"
class="wu-button wu-button-sm wu-button--outline"
data-lightbox-prev=""
>
← Previous
</button>
<button
type="button"
class="wu-button wu-button-sm wu-button--outline"
data-lightbox-next=""
>
Next →
</button>
</div>
<p>
<span data-lightbox-name></span>
<a class="wu-button wu-button-md wu-button--soft" data-download-photo href="#" download>
<i class="wu-icon wu-icon--cloud-download-gold wu-icon--md" aria-hidden="true"></i>
Download image
</a>
</p>
</div>
</div>
</div>
</div>
</div>
<div class="wu-guest-toast" role="status" aria-live="polite" data-toast hidden></div>
CSS reference & dependencies
.wu-guest-gallery-controls.wu-field.wu-guest-sort.wu-segment-control.wu-guest-gallery-grid.wu-guest-media.wu-guest-media__caption.wu-guest-media__actions.wu-button.wu-button-sm.wu-button--primary-light.wu-icon
Stylesheets · in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css
assets/css/wu-foundation.css
assets/css/wu-components.css
assets/css/wu-icons.css
public/assets/css/public.css
public/assets/css/guest-album.css
Scripts · once, in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js
public/assets/js/guest-album.js
Dependency paths below are relative to the project root. Source snippet asset paths are relative to public/. Adjust paths when moving a snippet.
Dependencies
Copy Dependencies
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link href="assets/css/wu-foundation.css" rel="stylesheet" />
<link href="assets/css/wu-components.css" rel="stylesheet" />
<link href="assets/css/wu-icons.css" rel="stylesheet" />
<link href="public/assets/css/public.css" rel="stylesheet" />
<link href="public/assets/css/guest-album.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
<script src="public/assets/js/guest-album.js"></script>
Two photo items and one video poster selected from the original grid; source controls and lightbox preserved.
Application voicemail player
Source: application/moderation.html · [data-voice-card]
voicemail.js changes the SVG wave, elapsed timer and .is-playing state. Only one card plays at a time.
This is a visual playback demo, not an HTMLAudioElement connected to a recording.
Details use the source dialog hook. Audio delivery/download is not implemented by this controller.
HTML example
HTML
Copy HTML
<div
class="wu-voicemail-card"
data-voice-card
data-sender="Mia & Ben"
data-duration="110"
data-elapsed="2"
>
<p class="wu-voicemail-from">
from:
<strong>Mia & Ben</strong>
</p>
<button
class="wu-voicemail-open"
type="button"
data-voice-open
aria-expanded="false"
aria-controls="voicemailDetails1"
aria-label="Show voicemail details from Mia and Ben"
data-modal-open="lightboxDialog"
data-bs-toggle="modal"
data-bs-target="#lightboxDialog"
>
<i class="wu-icon wu-icon--arrow-top-right wu-icon--md"></i>
</button>
<div class="wu-voicemail-player">
<button
class="wu-voicemail-play"
type="button"
data-voice-play
aria-label="Play voicemail from Mia & Ben"
aria-pressed="false"
>
<i class="wu-voicemail-icon wu-voicemail-icon--play" aria-hidden="true"></i>
<i class="wu-voicemail-icon wu-voicemail-icon--pause" aria-hidden="true"></i>
</button>
<img
class="wu-voicemail-wave"
data-voice-wave
src="../assets/images/voicemail-wave-idle.svg"
data-idle="../assets/images/voicemail-wave-idle.svg"
data-playing="../assets/images/voicemail-wave-playing.svg"
width="197"
height="32"
alt=""
aria-hidden="true"
/>
<p class="wu-voicemail-time">
<span data-voice-elapsed>0:02</span>
/
<span>1:50</span>
</p>
</div>
</div>
<div
class="wu-voicemail-card"
data-voice-card
data-sender="Mia & Ben"
data-duration="110"
data-elapsed="2"
>
<p class="wu-voicemail-from">
from:
<strong>Mia & Ben</strong>
</p>
<button
class="wu-voicemail-open"
type="button"
data-voice-open
aria-expanded="false"
aria-controls="voicemailDetails2"
aria-label="Show voicemail details from Mia and Ben"
>
<i class="wu-icon wu-icon--arrow-top-right wu-icon--md"></i>
</button>
<div class="wu-voicemail-player">
<button
class="wu-voicemail-play"
type="button"
data-voice-play
aria-label="Play voicemail from Mia & Ben"
aria-pressed="false"
>
<i class="wu-voicemail-icon wu-voicemail-icon--play" aria-hidden="true"></i>
<i class="wu-voicemail-icon wu-voicemail-icon--pause" aria-hidden="true"></i>
</button>
<img
class="wu-voicemail-wave"
data-voice-wave
src="../assets/images/voicemail-wave-idle.svg"
data-idle="../assets/images/voicemail-wave-idle.svg"
data-playing="../assets/images/voicemail-wave-playing.svg"
width="197"
height="32"
alt=""
aria-hidden="true"
/>
<p class="wu-voicemail-time">
<span data-voice-elapsed>0:02</span>
/
<span>1:50</span>
</p>
</div>
</div>
<!-- Related source overlay blocks required by these triggers. -->
<div
class="wu-modal modal fade"
id="lightboxDialog"
tabindex="-1"
aria-labelledby="lightboxDialogTitle"
aria-modal="true"
role="dialog"
>
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div class="modal-content">
<div class="wu-modal-head modal-header">
<h2 class="text-bronze-600 fw-bold" id="lightboxDialogTitle">
Manage
<strong>IMG.592820.jpg</strong>
</h2>
<button
class="btn-close"
data-modal-close=""
type="button"
data-bs-dismiss="modal"
aria-label="Close"
></button>
</div>
<div class="modal-body">
<div class="wu-guest-lightbox">
<img
data-lightbox-image=""
alt="Guests smiling during the celebration"
src="../public/assets/images/memory-06.webp"
/>
</div>
<div class="wu-guestbook-voicemail-features">
<div class="wu-guestbook">
<h6>Guestbook</h6>
<div class="wu-guestbook-card wu-step-visual wu-step-visual--photos">
<div class="wu-guestbook-message">
<h5>
from:
<strong>Mia & Ben</strong>
</h5>
<p>“You two looked so happy. Thank you for letting us be part of it.”</p>
</div>
<div>
<img
alt=""
decoding="async"
height="50"
loading="lazy"
src="../public/assets/images/memory-01.webp"
width="74"
/>
<img
alt=""
decoding="async"
height="50"
loading="lazy"
src="../public/assets/images/memory-02.webp"
width="74"
/>
<img
alt=""
decoding="async"
height="50"
loading="lazy"
src="../public/assets/images/memory-03.webp"
width="74"
/>
<span class="wu-photo-stack-note ms-3">3 photos attached</span>
</div>
</div>
</div>
<div class="wu-guestbook">
<h6>Voicemail</h6>
<div
class="wu-voicemail-card"
data-voice-card
data-sender="Mia & Ben"
data-duration="110"
data-elapsed="2"
>
<p class="wu-voicemail-from">
from:
<strong>Mia & Ben</strong>
</p>
<button
class="wu-voicemail-open"
type="button"
data-voice-open
aria-expanded="false"
aria-controls="voicemailDetails1"
aria-label="Show voicemail details from Mia and Ben"
>
<i class="wu-icon wu-icon--arrow-top-right wu-icon--md"></i>
</button>
<div class="wu-voicemail-player">
<button
class="wu-voicemail-play"
type="button"
data-voice-play
aria-label="Play voicemail from Mia & Ben"
aria-pressed="false"
>
<i class="wu-voicemail-icon wu-voicemail-icon--play" aria-hidden="true"></i>
<i class="wu-voicemail-icon wu-voicemail-icon--pause" aria-hidden="true"></i>
</button>
<img
class="wu-voicemail-wave"
data-voice-wave
src="../assets/images/voicemail-wave-idle.svg"
data-idle="../assets/images/voicemail-wave-idle.svg"
data-playing="../assets/images/voicemail-wave-playing.svg"
width="197"
height="32"
alt=""
aria-hidden="true"
/>
<p class="wu-voicemail-time">
<span data-voice-elapsed>0:02</span>
/
<span>1:50</span>
</p>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer justify-content-between">
<button class="wu-button" type="button" data-bs-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
CSS reference & dependencies
.wu-voicemail-card.wu-voicemail-from.wu-voicemail-open.wu-icon.wu-icon--arrow-top-right.wu-icon--md.wu-voicemail-player.wu-voicemail-play.wu-voicemail-icon.wu-voicemail-icon--play.wu-voicemail-icon--pause.wu-voicemail-wave
Stylesheets · in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css
assets/css/wu-components.css
application/assets/css/application-shell.css
application/assets/css/application-features.css
public/assets/css/guest-album.css
application/assets/css/application-album.css
assets/css/wu-icons.css
Scripts · once, in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js
application/assets/js/voicemail.js
Dependency paths below are relative to the project root. Source snippet asset paths are relative to application/. Adjust paths when moving a snippet.
Dependencies
Copy Dependencies
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link href="assets/css/wu-components.css" rel="stylesheet" />
<link href="application/assets/css/application-shell.css" rel="stylesheet" />
<link href="application/assets/css/application-features.css" rel="stylesheet" />
<link href="public/assets/css/guest-album.css" rel="stylesheet" />
<link href="application/assets/css/application-album.css" rel="stylesheet" />
<link href="assets/css/wu-icons.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
<script src="application/assets/js/voicemail.js"></script>
Source controls preserved. One absolute file:///Users/... lightbox image is made portable using the identical supplied memory-06.webp asset; production source is unchanged.
Three templates, one related feature architecture. Template 1 keeps its upload/contribution stage inline. Templates 2 and 3 use contribution, preview and status dialogs. Keep the original root hooks and associated dialogs together; copying an inner guestbook textarea alone does not initialize its controller.
Configuration & theme
HTML
Copy HTML
<body
class="wu-guest wu-album1"
data-album-template="template-1"
data-enabled-guest-features="itinerary,registry,eventInfo,guestSeat,guestbook,voicemail,share"
>
data-album-template determines the album link. The body class selects template-specific layout and styling; .wu-guest supplies shared color variables. No runtime color picker exists on the supplied Guest pages. data-enabled-guest-features controls elements marked data-guest-feature; ?disabled=guestbook,voicemail removes those features for the demo. Keep theme overrides scoped to the guest context. See the independent Template 1 , Template 2 and Template 3 implementations.
Selector
Source properties
.wu-guest
--guest-bg: var(--wu-gold-50, #fbf8f2), --guest-ink:
var(--wu-neutral-900, #29241f), --guest-muted:
var(--wu-neutral-600, #665f59), --guest-line:
var(--wu-neutral-200, #e8e2da)
Template 1: upload, guestbook & voicemail
Source: public/guest-template-1.html · [data-inline-upload-stage] + #fileInput + #errorDialog
Choose a local image/video to add actual files to the selected-file list. The existing controller renders queued/uploading/complete/error states.
Guestbook and voicemail panels belong to this contribution cluster; do not move them outside their controller root.
Uploads are simulated in memory and never sent to an API. Use preview URL ?simulate=upload-error to exercise the existing retry branch.
Recording requires browser microphone permission and MediaRecorder. It is not automatically exercised by this documentation.
HTML example
HTML
Copy HTML
<div class="wu-guest-upload-stage" data-inline-upload-stage data-inline-dropzone>
<p>
Upload pictures or videos you want to share. Remain on this page until all uploads complete.
</p>
<button type="button" class="wu-guest-upload-stage__browse" data-choose-files>
<div
class="bg-gold-100 p-2 rounded-circle d-flex align-items-center justify-content-center mb-2"
>
<i class="wu-icon wu-icon--cloud-upload wu-icon--md" aria-hidden="true"></i>
</div>
<h5 class="mb-0">Browse files</h5>
<small>Choose photos or videos from your device</small>
</button>
<div class="wu-guest-upload-review" data-upload-review tabindex="-1">
<div class="wu-guest-upload-review__head">
<strong class="text-gold-500" data-file-count>3 files selected</strong>
<button type="button" class="wu-button wu-button-sm wu-button--soft" data-choose-files>
Add more +
</button>
</div>
<div class="wu-guest-files" data-file-list aria-label="Selected files">
<div class="wu-guest-file wu-guest-inline-file" data-state="queued">
<img src="assets/images/memory-01.webp" alt="" />
<div class="wu-guest-inline-file__info">
<div class="d-flex align-items-center gap-2">
<strong>ceremony-photo.jpg</strong>
<small>2.4 MB</small>
</div>
<a type="button" class="wu-guest-inline-file__preview text-decoration-none text-gold-500">
Preview
</a>
</div>
<div class="wu-guest-inline-file__actions">
<button
type="button"
class="wu-button wu-button--danger wu-button-sm wu-guest-inline-file__remove"
aria-label="Remove guest-message.mp4"
>
<i class="wu-icon wu-icon--trash wu-icon--sm" aria-hidden="true"></i>
</button>
</div>
</div>
<!-- Sedang upload -->
<div class="wu-guest-file wu-guest-inline-file" data-state="uploading">
<img src="assets/images/memory-02.webp" alt="" />
<div class="wu-guest-inline-file__info">
<div class="d-flex align-items-center gap-2">
<strong>first-dance.jpg</strong>
<small>3.1 MB</small>
</div>
<span class="wu-guest-inline-file__status">Uploading 50%</span>
<div
class="wu-guest-inline-progress"
role="progressbar"
aria-label="Preview progress for first-dance.jpg"
aria-valuemin="0"
aria-valuemax="100"
aria-valuenow="50"
>
<span style="width: 50%"></span>
</div>
</div>
<div class="wu-guest-inline-file__actions">
<button
type="button"
class="wu-guest-inline-file__remove wu-button wu-button-sm wu-button--outline--light"
aria-label="Cancel first-dance.jpg"
>
Cancel
</button>
</div>
</div>
<!-- Upload gagal -->
<div class="wu-guest-file wu-guest-inline-file" data-state="error">
<img class="wu-guest-file__type" src="../assets/images/placeholder-interrupt.png" alt="" />
<div class="wu-guest-inline-file__info">
<div class="d-flex align-items-center gap-2">
<strong>guest-message.mp4</strong>
<small>18.6 MB</small>
</div>
<span class="wu-guest-inline-file__status">Unstable Internet Connection</span>
</div>
<div class="wu-guest-inline-file__actions">
<button
type="button"
class="wu-button wu-button-sm wu-button--danger wu-guest-inline-file__retry"
>
<i class="wu-icon wu-icon--retry wu-icon--sm" aria-hidden="true"></i>
Retry
</button>
<button
type="button"
class="wu-button wu-button--danger wu-button-sm wu-guest-inline-file__remove d-none d-sm-inline"
aria-label="Remove guest-message.mp4"
>
<i class="wu-icon wu-icon--trash wu-icon--sm" aria-hidden="true"></i>
</button>
</div>
</div>
</div>
</div>
<div class="wu-guest-upload-stage__extras">
<button
type="button"
data-upload-tab="message"
data-guest-feature="guestbook"
aria-pressed="false"
>
<i class="wu-icon wu-icon--envelope-combine wu-icon--sm" aria-hidden="true"></i>
Leave us a Message
<span>(Optional)</span>
</button>
<div class="vr d-sm-block"></div>
<button
type="button"
data-upload-tab="voice"
data-guest-feature="voicemail"
aria-pressed="false"
>
<i class="wu-icon wu-icon--microphone-combine wu-icon--sm" aria-hidden="true"></i>
Record Voice Message
<span>(Optional)</span>
</button>
</div>
<div class="wu-guest-upload-extras" data-inline-extras hidden>
<div class="wu-guest-extra-panel" data-upload-content="message" data-guest-feature="guestbook">
<p class="mb-0 text-gold-500 fw-bold">LEAVE US A MESSAGE</p>
<p>Personalize your upload with a name and a message. Submit with file upload.</p>
<div class="wu-field wu-guest-inline-fields">
<div>
<label class="form-label wu-field-label" for="guestName">Your name</label>
<input class="wu-control" id="guestName" autocomplete="name" placeholder="Your name" />
</div>
<div>
<label class="form-label wu-field-label" for="guestMessage">Message</label>
<textarea
class="wu-control"
id="guestMessage"
maxlength="255"
rows="3"
placeholder="Write a message"
></textarea>
<small data-message-count>0 / 255</small>
</div>
</div>
<button type="button" class="wu-button wu-button-sm wu-button--soft mt-4" data-save-message>
Save message
<i class="wu-icon wu-icon--arrow-right-gold wu-icon--sm" aria-hidden="true"></i>
</button>
</div>
<div
class="wu-guest-extra-panel"
data-upload-content="voice"
data-guest-feature="voicemail"
hidden
>
<p class="mb-0 text-gold-500 fw-bold">LEAVE US A VOICEMAIL / RECORD MESSAGE</p>
<p>
Record and upload a personal, voice only message that is private to the host of the event.
Voice messages do not appear in the public gallery and are uploaded separately from photos
and videos.
</p>
<label class="form-label wu-field-label" for="voiceName">Your name</label>
<input class="wu-control" id="voiceName" autocomplete="name" placeholder="Your name" />
<div class="wu-guest-recorder">
<button type="button" class="wu-guest-recorder__button" data-record aria-pressed="false">
<span></span>
<b>Record</b>
</button>
<div class="wu-guest-wave" aria-hidden="true">
<img src="../assets/images/soundwave.svg" alt="" />
</div>
<strong class="wu-font-display" data-record-time>00:00</strong>
<audio controls data-voice-preview hidden></audio>
<small aria-live="polite" data-record-status class="text-neutral-500">
Tap button record above to record a voicemail recording.
</small>
</div>
<button type="button" class="wu-button wu-button-sm wu-button--soft mt-4" data-save-message>
Save voicemail
<i class="wu-icon wu-icon--arrow-right-gold wu-icon--sm" aria-hidden="true"></i>
</button>
</div>
<p
class="wu-guest-inline-contribution-status"
data-inline-contribution-status
role="status"
hidden
></p>
</div>
<div
class="wu-guest-inline-status"
data-inline-upload-status
data-state="idle"
role="region"
aria-label="Upload status"
tabindex="-1"
hidden
>
<div class="wu-guest-inline-status__head">
<strong data-inline-status-title>Uploading your memories</strong>
<span data-inline-status-percent>0%</span>
</div>
<p data-inline-status-copy>Preparing your files…</p>
<div
class="progress"
role="progressbar"
aria-label="Overall upload progress"
aria-valuemin="0"
aria-valuemax="100"
aria-valuenow="0"
>
<div class="progress-bar" data-inline-status-bar style="width: 0%"></div>
</div>
<div
class="wu-alert mt-3 mb-0"
data-inline-status-alert
role="status"
aria-live="polite"
hidden
></div>
<button
type="button"
class="wu-button wu-button-sm wu-button--outline mt-3"
data-inline-status-done
hidden
>
Review files
</button>
</div>
<hr />
<button
disabled
type="button"
class="wu-button wu-button-sm wu-button--primary-light"
data-start-upload
>
Upload to Album
<i class="wu-icon wu-icon--cloud-upload-white wu-icon--sm" aria-hidden="true"></i>
</button>
<a href="#sharedGallery" class="wu-guest-jump">Looking for photos? Jump to Gallery ↓</a>
</div>
<input id="fileInput" type="file" accept="image/*,video/*" multiple hidden />
<div
class="modal fade wu-guest-dialog"
id="errorDialog"
tabindex="-1"
aria-labelledby="errorDialogTitle"
aria-hidden="true"
>
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header">
<div>
<p class="wu-guest-eyebrow">Connection status</p>
<h2 id="errorDialogTitle">Oops! Your Google Drive is disconnected</h2>
</div>
<button
type="button"
class="btn-close"
data-dialog-close
aria-label="Close"
data-bs-dismiss="modal"
></button>
</div>
<div class="modal-body">
<div class="wu-guest-feedback wu-guest-feedback--error">
<span aria-hidden="true">✖</span>
<p data-error-description>
Your selected files remain available. Please retry after the album owner reconnects
Google Drive.
</p>
<div class="wu-guest-error-actions">
<button
class="wu-button wu-button-sm wu-button--outline"
type="button"
data-retry-upload
>
Retry upload
</button>
<button
class="wu-button wu-button-sm wu-button--danger"
type="button"
data-dialog-open="reportDialog"
data-bs-toggle="modal"
data-bs-target="#reportDialog"
>
Report issue
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="modal fade wu-guest-dialog"
id="reportDialog"
tabindex="-1"
aria-labelledby="reportDialogTitle"
aria-hidden="true"
>
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header bg-neutral-0 border-0">
<button
type="button"
class="btn-close"
data-dialog-close
aria-label="Close"
data-bs-dismiss="modal"
></button>
</div>
<div class="modal-body">
<div class="wu-guest-feedback text-center border-0">
<img src="../assets/icons/info.svg" />
<h5 class="mt-4 mb-2">Did you run into any issues?</h5>
<p class="mb-4">
We want to make sure everything works smoothly for you. Please let us know if you faced
any trouble so we can fix it right away.
</p>
<a
class="wu-button wu-button-md wu-button--soft"
data-report-link
href="mailto:support@weduploader.com"
>
<i class="wu-icon wu-icon--envelope-combine wu-icon--sm" aria-hidden="true"></i>
Reach us via Email
</a>
</div>
</div>
</div>
</div>
</div>
<div class="wu-guest-toast" role="status" aria-live="polite" data-toast hidden></div>
CSS reference & dependencies
.wu-guest-upload-stage.wu-guest-upload-stage__browse.wu-icon.wu-icon--cloud-upload.wu-icon--md.wu-guest-upload-review.wu-guest-upload-review__head.wu-button.wu-button-sm.wu-button--soft.wu-guest-files.wu-guest-file
Stylesheets · in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css
assets/css/wu-foundation.css
assets/css/wu-components.css
assets/css/wu-icons.css
public/assets/css/public.css
public/assets/css/guest-album.css
Scripts · once, in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js
public/assets/js/guest-album.js
Dependency paths below are relative to the project root. Source snippet asset paths are relative to public/. Adjust paths when moving a snippet.
Dependencies
Copy Dependencies
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link href="assets/css/wu-foundation.css" rel="stylesheet" />
<link href="assets/css/wu-components.css" rel="stylesheet" />
<link href="assets/css/wu-icons.css" rel="stylesheet" />
<link href="public/assets/css/public.css" rel="stylesheet" />
<link href="public/assets/css/guest-album.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
<script src="public/assets/js/guest-album.js"></script>
Source excerpt; no component class renaming.
Templates 2 & 3: contribution dialogs
Source: public/guest-template-2.html · #uploadDialog + #uploadPreviewDialog + #uploadStatusDialog
Templates 2 and 3 are separate HTML pages sharing guest-album.css and guest-album.js. Template 1 uses its own inline upload root.
Keep the review, file row template, status and preview dialogs together. The source waits for hidden/shown Bootstrap events during handoff.
The source provides simulated upload failure and retry, Guestbook draft and microphone recording. No network upload or persistence backend is supplied.
HTML example
HTML
Copy HTML
<button
type="button"
class="wu-button wu-button-lg wu-button--primary-light mx-0 mx-xl-4"
data-choose-files
>
<i class="wu-icon wu-icon--cloud-upload-white wu-icon--md" aria-hidden="true"></i>
Upload
</button>
<div
class="modal fade wu-guest-dialog wu-guest-dialog--upload"
id="uploadDialog"
tabindex="-1"
aria-labelledby="uploadDialogTitle"
aria-hidden="true"
>
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable modal-lg">
<div class="modal-content">
<div class="modal-header">
<div>
<p class="wu-guest-eyebrow text-gold-500 mb-0">SHARE YOUR VIEW OF THE DAY</p>
<h2 id="uploadDialogTitle" class="wu-font-display">Upload your photos & videos</h2>
</div>
<button
type="button"
class="btn-close"
data-dialog-close
aria-label="Close"
data-bs-dismiss="modal"
></button>
</div>
<div class="modal-body">
<div class="wu-guest-upload-drop">
<button type="button" class="wu-guest-upload-drop__button" data-choose-files>
<div
class="bg-gold-100 p-2 rounded-circle d-flex align-items-center justify-content-center mb-2"
>
<i class="wu-icon wu-icon--cloud-upload wu-icon--md" aria-hidden="true"></i>
</div>
<h5 class="mb-0">Browse files</h5>
<small>Choose photos or videos from your device</small>
</button>
</div>
<div class="wu-guest-upload-review" data-upload-review hidden>
<div class="wu-guest-upload-review__head">
<strong class="text-gold-500" data-file-count>0 files selected</strong>
<button type="button" class="wu-button wu-button-sm wu-button--soft" data-choose-files>
Add more +
</button>
</div>
<div class="wu-guest-files" data-file-list aria-label="Selected files"></div>
<template data-upload-row>
<div class="wu-guest-file wu-guest-inline-file" data-state="queued">
<img src="" alt="" />
<div class="wu-guest-inline-file__info">
<div class="d-flex align-items-center gap-2">
<strong></strong>
<small></small>
</div>
<button
type="button"
class="wu-guest-inline-file__preview text-decoration-none text-gold-500"
>
Preview
</button>
<span class="wu-guest-inline-file__status" hidden></span>
<div
class="wu-guest-inline-progress"
role="progressbar"
aria-valuemin="0"
aria-valuemax="100"
aria-valuenow="0"
hidden
>
<span style="width:0%"></span>
</div>
</div>
<div class="wu-guest-inline-file__actions">
<button
type="button"
class="wu-button wu-button-sm wu-button--danger wu-guest-inline-file__retry"
hidden
>
<i class="wu-icon wu-icon--retry wu-icon--sm" aria-hidden="true"></i>
Retry
</button>
<button
type="button"
class="wu-button wu-button-sm wu-button--danger wu-guest-inline-file__remove"
aria-label="Remove file"
>
<i class="wu-icon wu-icon--trash wu-icon--sm" aria-hidden="true"></i>
</button>
</div>
</div>
</template>
</div>
<div class="wu-guest-upload-stage__extras" role="group" aria-label="Optional contribution">
<button
type="button"
aria-pressed="false"
data-upload-tab="message"
data-guest-feature="guestbook"
disabled
>
<i class="wu-icon wu-icon--envelope-combine wu-icon--sm" aria-hidden="true"></i>
Leave us a Message
<span>(Optional)</span>
</button>
<div class="vr d-sm-block" aria-hidden="true"></div>
<button
type="button"
aria-pressed="false"
data-upload-tab="voice"
data-guest-feature="voicemail"
disabled
>
<i class="wu-icon wu-icon--microphone-combine wu-icon--sm" aria-hidden="true"></i>
Record Voice Message
<span>(Optional)</span>
</button>
</div>
<div class="wu-guest-upload-extras" data-modal-extras hidden>
<div
class="wu-guest-extra-panel"
data-upload-content="message"
data-guest-feature="guestbook"
hidden
>
<p class="mb-0 text-gold-500 fw-bold">LEAVE US A MESSAGE</p>
<p>Personalize your upload with a name and a message. Submit with file upload.</p>
<div class="wu-field wu-guest-inline-fields">
<div>
<label class="form-label wu-field-label" for="guestName">Your name</label>
<input
class="wu-control"
id="guestName"
autocomplete="name"
placeholder="Your name"
/>
</div>
<div>
<label class="form-label wu-field-label" for="guestMessage">Message</label>
<textarea
class="wu-control"
id="guestMessage"
maxlength="255"
rows="3"
placeholder="Write a message"
></textarea>
<small data-message-count>0 / 255</small>
</div>
</div>
<button
type="button"
class="wu-button wu-button-sm wu-button--soft mt-4"
data-save-message
>
Save message
<i class="wu-icon wu-icon--arrow-right-gold wu-icon--sm" aria-hidden="true"></i>
</button>
</div>
<div
class="wu-guest-extra-panel"
data-upload-content="voice"
data-guest-feature="voicemail"
hidden
>
<p class="mb-0 text-gold-500 fw-bold">LEAVE US A VOICEMAIL / RECORD MESSAGE</p>
<p>
Record and upload a personal, voice only message that is private to the host of the
event. Voice messages do not appear in the public gallery and are uploaded separately
from photos and videos.
</p>
<label class="form-label wu-field-label" for="voiceName">Your name</label>
<input class="wu-control" id="voiceName" autocomplete="name" placeholder="Your name" />
<div class="wu-guest-recorder">
<button
type="button"
class="wu-guest-recorder__button"
data-record
aria-pressed="false"
>
<span></span>
<b>Record</b>
</button>
<div class="wu-guest-wave" aria-hidden="true">
<img src="../assets/images/soundwave.svg" alt="" />
</div>
<strong class="wu-font-display" data-record-time>00:00</strong>
<audio controls data-voice-preview hidden></audio>
<small aria-live="polite" data-record-status class="text-neutral-500">
Tap button record above to record a voicemail recording.
</small>
</div>
<button
type="button"
class="wu-button wu-button-sm wu-button--soft mt-4"
data-save-message
>
Save voicemail
<i class="wu-icon wu-icon--arrow-right-gold wu-icon--sm" aria-hidden="true"></i>
</button>
</div>
<p
class="wu-guest-inline-contribution-status"
data-modal-contribution-status
role="status"
hidden
></p>
</div>
<div
class="wu-guest-upload-result"
data-upload-result
hidden
role="status"
aria-live="polite"
></div>
</div>
<div class="modal-footer justify-content-between">
<button
class="wu-button wu-button-md wu-button--outline"
type="button"
data-dialog-close
data-bs-dismiss="modal"
>
Cancel
</button>
<button
class="wu-button wu-button-md wu-button--primary"
type="button"
data-start-upload
disabled
>
<i class="wu-icon wu-icon--cloud-upload-white wu-icon--sm" aria-hidden="true"></i>
Upload to Album
</button>
</div>
</div>
</div>
</div>
<div
class="modal fade wu-guest-dialog wu-guest-dialog--upload-preview"
id="uploadPreviewDialog"
tabindex="-1"
aria-labelledby="uploadPreviewDialogTitle"
aria-hidden="true"
>
<div class="modal-dialog modal-dialog-centered modal-lg">
<div class="modal-content">
<div class="modal-header">
<h2 id="uploadPreviewDialogTitle" data-upload-preview-title>File preview</h2>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body wu-guest-upload-preview">
<img data-upload-preview-image alt="" hidden />
<video data-upload-preview-video controls playsinline hidden></video>
</div>
</div>
</div>
</div>
<div
class="modal fade wu-guest-dialog wu-guest-dialog--upload-status"
id="uploadStatusDialog"
tabindex="-1"
aria-labelledby="uploadStatusDialogTitle"
aria-hidden="true"
data-bs-backdrop="static"
data-bs-keyboard="false"
>
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<div>
<p class="wu-guest-eyebrow text-gold-500 mb-0">Upload status</p>
<h2 id="uploadStatusDialogTitle" class="wu-font-display" data-upload-status-title>
Uploading your memories
</h2>
</div>
<button
type="button"
class="btn-close"
data-upload-status-close
data-bs-dismiss="modal"
aria-label="Close"
hidden
></button>
</div>
<div class="modal-body">
<p data-upload-status-copy role="status" aria-live="polite">Preparing your files…</p>
<div class="progress" aria-label="Overall upload progress">
<div
class="progress-bar"
data-upload-overall-bar
role="progressbar"
aria-valuemin="0"
aria-valuemax="100"
aria-valuenow="0"
style="width: 0%"
></div>
</div>
<small class="d-block mt-2" data-upload-percent>0%</small>
<div
class="wu-alert wu-alert--success mt-4 mb-0"
data-upload-status-alert
role="alert"
hidden
></div>
</div>
<div class="modal-footer">
<button
type="button"
class="wu-button wu-button-md wu-button--primary"
data-upload-status-done
disabled
>
Done
</button>
</div>
</div>
</div>
</div>
<div
class="modal fade wu-guest-dialog"
id="errorDialog"
tabindex="-1"
aria-labelledby="errorDialogTitle"
aria-hidden="true"
>
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header">
<div>
<p class="wu-guest-eyebrow">Connection status</p>
<h2 id="errorDialogTitle">Oops! Your Google Drive is disconnected</h2>
</div>
<button
type="button"
class="btn-close"
data-dialog-close
aria-label="Close"
data-bs-dismiss="modal"
></button>
</div>
<div class="modal-body">
<div class="wu-guest-feedback wu-guest-feedback--error">
<span aria-hidden="true">✖</span>
<p data-error-description>
Your selected files remain available. Please retry after the album owner reconnects
Google Drive.
</p>
<div class="wu-guest-error-actions">
<button
class="wu-button wu-button-sm wu-button--outline"
type="button"
data-retry-upload
>
Retry upload
</button>
<button
class="wu-button wu-button-sm wu-button--danger"
type="button"
data-dialog-open="reportDialog"
data-bs-toggle="modal"
data-bs-target="#reportDialog"
>
Report issue
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="modal fade wu-guest-dialog"
id="reportDialog"
tabindex="-1"
aria-labelledby="reportDialogTitle"
aria-hidden="true"
>
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header bg-neutral-0 border-0">
<button
type="button"
class="btn-close"
data-dialog-close
aria-label="Close"
data-bs-dismiss="modal"
></button>
</div>
<div class="modal-body">
<div class="wu-guest-feedback text-center border-0">
<img src="../assets/icons/info.svg" />
<h5 class="mt-4 mb-2">Did you run into any issues?</h5>
<p class="mb-4">
We want to make sure everything works smoothly for you. Please let us know if you faced
any trouble so we can fix it right away.
</p>
<a
class="wu-button wu-button-md wu-button--soft"
data-report-link
href="mailto:support@weduploader.com"
>
<i class="wu-icon wu-icon--envelope-combine wu-icon--sm" aria-hidden="true"></i>
Reach us via Email
</a>
</div>
</div>
</div>
</div>
</div>
<input id="fileInput" type="file" accept="image/*,video/*" multiple hidden />
<div class="wu-guest-toast" role="status" aria-live="polite" data-toast hidden></div>
CSS reference & dependencies
.wu-button.wu-button-lg.wu-button--primary-light.wu-icon.wu-icon--cloud-upload-white.wu-icon--md.wu-guest-dialog.wu-guest-dialog--upload.wu-guest-eyebrow.wu-font-display.wu-guest-upload-drop.wu-guest-upload-drop__button
Stylesheets · in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css
assets/css/wu-foundation.css
assets/css/wu-components.css
assets/css/wu-icons.css
public/assets/css/public.css
public/assets/css/guest-album.css
Scripts · once, in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js
public/assets/js/guest-album.js
Dependency paths below are relative to the project root. Source snippet asset paths are relative to public/. Adjust paths when moving a snippet.
Dependencies
Copy Dependencies
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link href="assets/css/wu-foundation.css" rel="stylesheet" />
<link href="assets/css/wu-components.css" rel="stylesheet" />
<link href="assets/css/wu-icons.css" rel="stylesheet" />
<link href="public/assets/css/public.css" rel="stylesheet" />
<link href="public/assets/css/guest-album.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
<script src="public/assets/js/guest-album.js"></script>
Source excerpt; no component class renaming.
Save & Share
Source: public/guest-template-1.html · #shareDialog / [data-save-album] / #albumLink
The guest controller derives the album URL from data-album-template and manages a browser-local saved-album list.
Clipboard requires browser support; the source falls back to selecting the link. Browser-local saving is not an account bookmark API.
HTML example
HTML
Copy HTML
<button
class="wu-button wu-button--ghost"
type="button"
data-dialog-open="shareDialog"
data-guest-feature="share"
data-bs-toggle="modal"
data-bs-target="#shareDialog"
>
<i class="wu-icon wu-icon--share wu-icon--sm" aria-hidden="true"></i>
<span class="d-none d-sm-block">Share Album</span>
</button>
<div
class="modal fade wu-guest-dialog"
id="shareDialog"
tabindex="-1"
aria-labelledby="shareDialogTitle"
aria-hidden="true"
>
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header d-flex align-items-center justify-content-between">
<h2 id="shareDialogTitle" class="wu-font-display">Share Albums</h2>
<button
type="button"
class="btn-close"
data-dialog-close
aria-label="Close"
data-bs-dismiss="modal"
></button>
</div>
<div class="modal-body">
<div class="wu-guest-share">
<div class="wu-guest-qr" aria-label="QR visual preview for the album" role="img">
<img
src="assets/images/06-tools/qr-preview.svg"
alt="Example QR code pointing to WedUploader"
/>
</div>
<div class="text-center text-sm-start">
<h3 class="wu-font-display">Share with another guest</h3>
<p class="text-neutral-500">
Scan the QR code or send the album link. Guests do not need an account
</p>
<div class="wu-field">
<label class="form-label wu-field-label d-none d-sm-block" for="albumLink">
Album link
</label>
<div class="wrapper d-flex flex-row align-items-center justify-content-center gap-2">
<div class="input-group">
<span class="input-group-text">
<i class="wu-icon wu-icon--link wu-icon--sm" aria-hidden="true"></i>
</span>
<input
disabled
type="text"
class="form-control form-control-lg"
value="https://weduploader.com/upload/9Q7kessLV2yo4fLt"
/>
<span class="input-group-text">
<i class="wu-icon wu-icon--copy wu-icon--sm" aria-hidden="true"></i>
</span>
</div>
<a
href="https://weduploader.com/upload/9Q7kessLV2yo4fLt"
class="wu-button wu-button-sm wu-button--soft"
type="button"
>
Visit
<i class="wu-icon wu-icon--arrow-right-gold wu-icon--xs" aria-hidden="true"></i>
</a>
</div>
</div>
</div>
</div>
<hr />
<div class="wu-guest-save text-center text-sm-start">
<h5 class="wu-font-display">Want to come back later?</h5>
<p class="text-neutral-500 mb-0">
Use “save album” to keep this guest album in this prototype browser. You can also
bookmark the page normally.
</p>
</div>
</div>
<div class="modal-footer align-items-start justify-content-start">
<button
class="wu-button wu-button-md wu-button--outline--light"
type="button"
data-save-album
>
<i class="wu-icon wu-icon--love wu-icon--md" aria-hidden="true"></i>
Save Album
</button>
</div>
</div>
</div>
</div>
<div class="wu-guest-toast" role="status" aria-live="polite" data-toast hidden></div>
CSS reference & dependencies
.wu-button.wu-button--ghost.wu-icon.wu-icon--share.wu-icon--sm.wu-guest-dialog.wu-font-display.wu-guest-share.wu-guest-qr.wu-field.wu-field-label.wu-icon--link
Stylesheets · in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css
assets/css/wu-foundation.css
assets/css/wu-components.css
assets/css/wu-icons.css
public/assets/css/public.css
public/assets/css/guest-album.css
Scripts · once, in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js
public/assets/js/guest-album.js
Dependency paths below are relative to the project root. Source snippet asset paths are relative to public/. Adjust paths when moving a snippet.
Dependencies
Copy Dependencies
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link href="assets/css/wu-foundation.css" rel="stylesheet" />
<link href="assets/css/wu-components.css" rel="stylesheet" />
<link href="assets/css/wu-icons.css" rel="stylesheet" />
<link href="public/assets/css/public.css" rel="stylesheet" />
<link href="public/assets/css/guest-album.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
<script src="public/assets/js/guest-album.js"></script>
Source excerpt; no component class renaming.
Guest information & seat search
Source: public/guest-template-1.html · #itineraryDialog / #registryDialog / #eventInfoDialog / #seatDialog
Feature visibility is driven by data-enabled-guest-features and the optional disabled query list.
Itinerary tabs and Guest Seats search use the actual guest controller. Search uses a hardcoded demo guest list; it is not a seating API.
Registry links marked data-demo-link need the couple’s destination URL in production.
HTML example
HTML
Copy HTML
<button
class="wu-guest-action"
type="button"
data-dialog-open="itineraryDialog"
data-guest-feature="itinerary"
data-bs-toggle="modal"
data-bs-target="#itineraryDialog"
>
<div
class="bg-gold-100 p-2 p-sm-3 rounded-circle d-flex align-items-center justify-content-center"
>
<i class="wu-icon wu-icon--itinerary wu-icon--md" aria-hidden="true"></i>
</div>
<span class="text-title">
Event
<br />
Itineraries
</span>
</button>
<div
class="modal fade wu-guest-dialog"
id="itineraryDialog"
tabindex="-1"
aria-labelledby="itineraryDialogTitle"
aria-hidden="true"
>
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header">
<div>
<h2 id="itineraryDialogTitle" class="wu-font-display">Event Itineraries</h2>
</div>
<button
type="button"
class="btn-close"
data-dialog-close
aria-label="Close"
data-bs-dismiss="modal"
></button>
</div>
<div class="modal-body">
<div
class="wu-segment-control d-flex flex-column flex-sm-row bg-gold-100 p-2 w-100"
role="group"
aria-label="Itinerary day"
>
<button type="button" class="is-active" aria-pressed="true" data-day="friday">
Friday, 13 June
</button>
<button type="button" aria-pressed="false" data-day="saturday">Saturday, 14 June</button>
</div>
<div class="wu-guest-itinerary" data-day-panel="friday">
<article>
<time class="d-none d-sm-flex">16:00</time>
<div class="order-2 order-sm-1">
<strong>Welcome gathering</strong>
<p class="align-self-center">
<i class="wu-icon wu-icon--location wu-icon--sm"></i>
Meadow House · Garden Room
</p>
</div>
<div class="order-1 order-sm-2 d-flex align-items-center justify-content-between">
<time class="d-inline d-sm-none">16:00</time>
<button class="wu-button wu-button-sm wu-button--soft" type="button">
Maps
<i class="wu-icon wu-icon--maps wu-icon--sm"></i>
</button>
</div>
</article>
<article>
<time class="d-none d-sm-flex">19:00</time>
<div class="order-2 order-sm-1">
<strong>Rehearsal dinner</strong>
<p class="align-self-center">
<i class="wu-icon wu-icon--location wu-icon--sm"></i>
Meadow House · Terrace
</p>
</div>
<div class="order-1 order-sm-2 d-flex align-items-center justify-content-between">
<time class="d-inline d-sm-none">16:00</time>
<button class="wu-button wu-button-sm wu-button--soft" type="button">
Maps
<i class="wu-icon wu-icon--maps wu-icon--sm"></i>
</button>
</div>
</article>
</div>
<div class="wu-guest-itinerary" data-day-panel="saturday" hidden>
<article>
<time class="d-none d-sm-flex">16:30</time>
<div class="order-2 order-sm-1">
<strong>Garden ceremony</strong>
<p class="align-self-center">
<i class="wu-icon wu-icon--location wu-icon--sm"></i>
Meadow House · Main lawn
</p>
</div>
<div class="order-1 order-sm-2 d-flex align-items-center justify-content-between">
<time class="d-inline d-sm-none">16:00</time>
<button class="wu-button wu-button-sm wu-button--soft" type="button">
Maps
<i class="wu-icon wu-icon--maps wu-icon--sm"></i>
</button>
</div>
</article>
<article>
<time class="d-none d-sm-flex">18:00</time>
<div class="order-2 order-sm-1">
<strong>Dinner and reception</strong>
<p class="align-self-center">
<i class="wu-icon wu-icon--location wu-icon--sm"></i>
Meadow House · Main lawn
</p>
</div>
<div class="order-1 order-sm-2 d-flex align-items-center justify-content-between">
<time class="d-inline d-sm-none">16:00</time>
<button class="wu-button wu-button-sm wu-button--soft" type="button">
Maps
<i class="wu-icon wu-icon--maps wu-icon--sm"></i>
</button>
</div>
</article>
<article>
<time class="d-none d-sm-flex">21:00</time>
<div class="order-2 order-sm-1">
<strong>Dancing</strong>
<p class="align-self-center">
<i class="wu-icon wu-icon--location wu-icon--sm"></i>
Meadow House · Main lawn
</p>
</div>
<div class="order-1 order-sm-2 d-flex align-items-center justify-content-between">
<time class="d-inline d-sm-none">16:00</time>
<button class="wu-button wu-button-sm wu-button--soft" type="button">
Maps
<i class="wu-icon wu-icon--maps wu-icon--sm"></i>
</button>
</div>
</article>
</div>
</div>
</div>
</div>
</div>
<button
class="wu-guest-action"
type="button"
data-dialog-open="registryDialog"
data-guest-feature="registry"
data-bs-toggle="modal"
data-bs-target="#registryDialog"
>
<div
class="bg-gold-100 p-2 p-sm-3 rounded-circle d-flex align-items-center justify-content-center"
>
<i class="wu-icon wu-icon--gift wu-icon--md" aria-hidden="true"></i>
</div>
<span class="text-title">
Gift
<br />
Registries
</span>
</button>
<div
class="modal fade wu-guest-dialog"
id="registryDialog"
tabindex="-1"
aria-labelledby="registryDialogTitle"
aria-hidden="true"
>
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header">
<div>
<h2 id="registryDialogTitle" class="wu-font-display">Gift Registries</h2>
</div>
<button
type="button"
class="btn-close"
data-dialog-close
aria-label="Close"
data-bs-dismiss="modal"
></button>
</div>
<div class="modal-body">
<p>The couple has registered at the places below.</p>
<div class="wu-guest-info-list">
<article>
<img class="gift-thumbnail border-0 rounded" src="../assets/images/gift-1.png" alt="" />
<div class="text-instruction">
<h3 class="mb-0">Target Gift Registry</h3>
<p class="mb-2">Wedding gift ideas selected by Sophia & Ethan.</p>
<div class="wu-field d-flex gap-2">
<div
class="wrapper d-flex flex-row align-items-center justify-content-center gap-2"
>
<div class="input-group">
<span class="input-group-text">
<i class="wu-icon wu-icon--link wu-icon--sm" aria-hidden="true"></i>
</span>
<input
disabled
type="text"
class="form-control form-control-lg"
value="https://weduploader.com/upload/9Q7kessLV2yo4fLt"
/>
<span class="input-group-text">
<i class="wu-icon wu-icon--copy wu-icon--sm" aria-hidden="true"></i>
</span>
</div>
<a
href="https://weduploader.com/upload/9Q7kessLV2yo4fLt"
class="wu-button wu-button-sm wu-button--soft"
type="button"
>
<span class="d-none d-sm-flex">Visit</span>
<i class="wu-icon wu-icon--arrow-right-gold wu-icon--xs" aria-hidden="true"></i>
</a>
</div>
<img
class="d-flex d-sm-none"
src="assets/images/06-tools/qr-preview.svg"
alt="Example QR code pointing to WedUploader"
width="48"
height="48"
/>
</div>
</div>
<div class="wu-guest-mini-qr d-none d-sm-flex" aria-hidden="true">
<img
src="assets/images/06-tools/qr-preview.svg"
alt="Example QR code pointing to WedUploader"
/>
</div>
</article>
<article>
<img class="gift-thumbnail border-0 rounded" src="../assets/images/gift-2.png" alt="" />
<div class="text-instruction">
<h3 class="mb-0">Amazon Gift Registry</h3>
<p class="mb-2">More ways to celebrate with the couple.</p>
<div class="wu-field d-flex gap-2">
<div
class="wrapper d-flex flex-row align-items-center justify-content-center gap-2"
>
<div class="input-group">
<span class="input-group-text">
<i class="wu-icon wu-icon--link wu-icon--sm" aria-hidden="true"></i>
</span>
<input
disabled
type="text"
class="form-control form-control-lg"
value="https://weduploader.com/upload/9Q7kessLV2yo4fLt"
/>
<span class="input-group-text">
<i class="wu-icon wu-icon--copy wu-icon--sm" aria-hidden="true"></i>
</span>
</div>
<a
href="https://weduploader.com/upload/9Q7kessLV2yo4fLt"
class="wu-button wu-button-sm wu-button--soft"
type="button"
>
<span class="d-none d-sm-flex">Visit</span>
<i class="wu-icon wu-icon--arrow-right-gold wu-icon--xs" aria-hidden="true"></i>
</a>
</div>
<img
class="d-flex d-sm-none"
src="assets/images/06-tools/qr-preview.svg"
alt="Example QR code pointing to WedUploader"
width="48"
height="48"
/>
</div>
</div>
<div class="wu-guest-mini-qr d-none d-sm-flex" aria-hidden="true">
<img
src="assets/images/06-tools/qr-preview.svg"
alt="Example QR code pointing to WedUploader"
/>
</div>
</article>
</div>
</div>
</div>
</div>
</div>
<button
class="wu-guest-action"
type="button"
data-dialog-open="eventInfoDialog"
data-guest-feature="eventInfo"
data-bs-toggle="modal"
data-bs-target="#eventInfoDialog"
>
<div
class="bg-gold-100 p-2 p-sm-3 rounded-circle d-flex align-items-center justify-content-center"
>
<i class="wu-icon wu-icon--info wu-icon--md" aria-hidden="true"></i>
</div>
<span class="text-title">
Event
<br />
Information
</span>
</button>
<div
class="modal fade wu-guest-dialog"
id="eventInfoDialog"
tabindex="-1"
aria-labelledby="eventInfoDialogTitle"
aria-hidden="true"
>
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header">
<div>
<h2 id="eventInfoDialogTitle" class="wu-font-display">Event Information</h2>
</div>
<button
type="button"
class="btn-close"
data-dialog-close
aria-label="Close"
data-bs-dismiss="modal"
></button>
</div>
<div class="modal-body">
<p>Extra links the couples wanted you to know about</p>
<div class="wu-guest-info-list">
<article>
<div
class="icons bg-gold-50 p-3 rounded align-items-center justify-content-center d-none d-sm-flex"
>
<i class="wu-icon wu-icon--list wu-icon--md"></i>
</div>
<div class="text-instruction order-2 order-sm-1">
<h3 class="mb-0">Uber Voucher</h3>
<p class="mb-2">
Let Uber take care of your event rides and meal needs with Vouchers. Cover the cost
of your guest’s rides and meals.
</p>
<div class="wu-field d-flex gap-2">
<div
class="wrapper d-flex flex-row align-items-center justify-content-center gap-2"
>
<div class="input-group">
<span class="input-group-text">
<i class="wu-icon wu-icon--link wu-icon--sm" aria-hidden="true"></i>
</span>
<input
disabled
type="text"
class="form-control form-control-lg"
value="https://weduploader.com/upload/9Q7kessLV2yo4fLt"
/>
<span class="input-group-text">
<i class="wu-icon wu-icon--copy wu-icon--sm" aria-hidden="true"></i>
</span>
</div>
<a
href="https://weduploader.com/upload/9Q7kessLV2yo4fLt"
class="wu-button wu-button-sm wu-button--soft"
type="button"
>
Visit
<i class="wu-icon wu-icon--arrow-right-gold wu-icon--xs" aria-hidden="true"></i>
</a>
</div>
</div>
</div>
<div class="wu-guest-mini-qr order-1 order-sm-2" aria-hidden="true">
<img
src="assets/images/06-tools/qr-preview.svg"
alt="Example QR code pointing to WedUploader"
/>
</div>
</article>
<article>
<div
class="icons bg-gold-50 p-3 rounded align-items-center justify-content-center d-none d-sm-flex"
>
<i class="wu-icon wu-icon--list wu-icon--md"></i>
</div>
<div class="text-instruction order-2 order-sm-1">
<h3 class="mb-0">Our Website for More Info</h3>
<p class="mb-2">The wedding website of Joe Guy and Jane Lady</p>
<div class="wu-field d-flex gap-2">
<div
class="wrapper d-flex flex-row align-items-center justify-content-center gap-2"
>
<div class="input-group">
<span class="input-group-text">
<i class="wu-icon wu-icon--link wu-icon--sm" aria-hidden="true"></i>
</span>
<input
disabled
type="text"
class="form-control form-control-lg"
value="https://weduploader.com/upload/9Q7kessLV2yo4fLt"
/>
<span class="input-group-text">
<i class="wu-icon wu-icon--copy wu-icon--sm" aria-hidden="true"></i>
</span>
</div>
<a
href="https://weduploader.com/upload/9Q7kessLV2yo4fLt"
class="wu-button wu-button-sm wu-button--soft"
type="button"
>
Visit
<i class="wu-icon wu-icon--arrow-right-gold wu-icon--xs" aria-hidden="true"></i>
</a>
</div>
</div>
</div>
<div class="wu-guest-mini-qr order-1 order-sm-2" aria-hidden="true">
<img
src="assets/images/06-tools/qr-preview.svg"
alt="Example QR code pointing to WedUploader"
/>
</div>
</article>
</div>
</div>
</div>
</div>
</div>
<button
class="wu-guest-action"
type="button"
data-dialog-open="seatDialog"
data-guest-feature="guestSeat"
data-bs-toggle="modal"
data-bs-target="#seatDialog"
>
<div
class="bg-gold-100 p-2 p-sm-3 rounded-circle d-flex align-items-center justify-content-center"
>
<i class="wu-icon wu-icon--seat wu-icon--md" aria-hidden="true"></i>
</div>
<span class="text-title">
Find
<br />
Your Seat
</span>
</button>
<div
class="modal fade wu-guest-dialog"
id="seatDialog"
tabindex="-1"
aria-labelledby="seatDialogTitle"
aria-hidden="true"
>
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header">
<div>
<h2 id="seatDialogTitle" class="wu-font-display">Find your seat</h2>
</div>
<button
type="button"
class="btn-close"
data-dialog-close
aria-label="Close"
data-bs-dismiss="modal"
></button>
</div>
<div class="modal-body">
<div class="wu-field">
<label class="form-label" for="seatSearch">Type your name</label>
<input
class="form-control form-control-lg"
id="seatSearch"
autocomplete="off"
placeholder="Type 'Olivia' for Preview Demo"
/>
<p class="wu-field-help" data-seat-hint>Enter at least 3 letters to find your table.</p>
</div>
<div class="wu-guest-seat-result" data-seat-result hidden>
<div>
<strong data-seat-name>Olivia Martin</strong>
<small>Reception · Garden Room</small>
</div>
<div class="table-number">
<h5 class="mb-0">08</h5>
<small>TABLE</small>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="wu-guest-toast" role="status" aria-live="polite" data-toast hidden></div>
CSS reference & dependencies
.wu-guest-action.wu-icon.wu-icon--itinerary.wu-icon--md.wu-guest-dialog.wu-font-display.wu-segment-control.wu-guest-itinerary.wu-icon--location.wu-icon--sm.wu-button.wu-button-sm
Stylesheets · in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css
assets/css/wu-foundation.css
assets/css/wu-components.css
assets/css/wu-icons.css
public/assets/css/public.css
public/assets/css/guest-album.css
Scripts · once, in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js
public/assets/js/guest-album.js
Dependency paths below are relative to the project root. Source snippet asset paths are relative to public/. Adjust paths when moving a snippet.
Dependencies
Copy Dependencies
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link href="assets/css/wu-foundation.css" rel="stylesheet" />
<link href="assets/css/wu-components.css" rel="stylesheet" />
<link href="assets/css/wu-icons.css" rel="stylesheet" />
<link href="public/assets/css/public.css" rel="stylesheet" />
<link href="public/assets/css/guest-album.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
<script src="public/assets/js/guest-album.js"></script>
Source excerpt; no component class renaming.
Ready-to-use content arrangements built from the components already in this guide. A page starter provides the document and shell; a layout pattern fills its content area. These samples do not replace production page content.
Copy into a starter. Open the
Public starter or
Application starter . Replace its placeholder content with one pattern, keep the surrounding shell, and load the listed dependencies once. New sample HTML and dependency paths are already relative to
documentation/starters/. Keep
data-page="new-page" in Application demos and add only the styling body classes explicitly stated below.
Insert sections inside the Public starter’s existing <main>. Content + media and CTA extend the previous examples; the grids and full FAQ composition reuse current homepage markup.
Public · Content + media
Source arrangement: public/about.html · .wu-page-hero .wu-page-hero-grid
Insert this whole section directly inside the Public starter <main>, replacing its placeholder section. Keep .container.wu-container and both copy/media columns.
Uses the Public starter’s existing stylesheets. The two source images and display utilities preserve the About page’s responsive image swap.
Sample copy is documentation-only. Update headings, CTA destinations and image alt text when reusing it.
HTML example Ready for the supplied page starter
HTML
Copy HTML
<!-- Paste inside Public starter <main>. Asset paths below target documentation/starters/. -->
<section class="wu-page-hero wu-about-first">
<div class="container wu-container">
<div class="wu-page-hero-grid">
<div class="wu-page-hero-copy">
<h1 class="wu-title">Every moment, collected together.</h1>
<p class="wu-lead">
Create a shared space for your celebration. Invite guests to add their favourite photos,
then revisit the day from every perspective.
</p>
<div class="wu-page-actions">
<a
class="wu-button wu-button--primary wu-button-lg"
href="../../public/create-album.html"
>
Create an album →
</a>
<a class="wu-text-link" href="../../public/tutorials.html">Read the guide →</a>
</div>
</div>
<div class="wu-page-visual px-2 px-xl-5">
<img
class="d-none d-sm-block d-md-none d-lg-block"
src="../../public/assets/images/03-about-us/01%20hero-about.webp"
alt="A collection of wedding memories and guest photographs"
decoding="async"
loading="lazy"
/>
<img
class="d-block d-sm-none d-md-block d-lg-none"
src="../../public/assets/images/03-about-us/01-2-about-hero-mobile.webp"
alt="A collection of wedding memories and guest photographs"
decoding="async"
loading="lazy"
/>
</div>
</div>
</div>
</section>
CSS reference & dependencies
.wu-page-hero.wu-about-first.wu-container.wu-page-hero-grid.wu-page-hero-copy.wu-title.wu-lead.wu-page-actions.wu-button.wu-button--primary.wu-button-lg.wu-text-link.wu-page-visual
Stylesheets · in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css
public/assets/css/components.css
public/assets/css/pages.css
public/assets/css/responsive.css
public/assets/css/site-shell.css
public/assets/css/public-layout.css
public/assets/css/public.css
assets/css/wu-icons.css
Scripts · once, in this order
No component JavaScript required.
The reference lists use project-root paths. The copyable dependency block and HTML below use paths relative to documentation/starters/, so they work in the delivered starter files. Load each dependency once; keep scripts after content. When moving your starter to public/ or application/, adjust those paths together. Keep its shell controller; a content-only preview does not need to reload it.
Dependencies
Copy Dependencies
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link href="../../public/assets/css/components.css" rel="stylesheet" />
<link href="../../public/assets/css/pages.css" rel="stylesheet" />
<link href="../../public/assets/css/responsive.css" rel="stylesheet" />
<link href="../../public/assets/css/site-shell.css" rel="stylesheet" />
<link href="../../public/assets/css/public-layout.css" rel="stylesheet" />
<link href="../../public/assets/css/public.css" rel="stylesheet" />
<link href="../../assets/css/wu-icons.css" rel="stylesheet" />
Existing page-intro example extended with sample copy and descriptive image alt text; page-scroll animation attributes omitted for standalone reuse.
Public · Feature grid
Source arrangement: public/index.html · #features > .container.wu-container > .wu-latest-feature-head + .wu-latest-feature-grid
Insert inside the Public starter <main>. This source composition contains one photo and four feature cards; keep all five grid items and their order.
Add class="wu-home-latest" to the Public starter body for the existing homepage section spacing. Keep a new data-page value such as new-public.html; do not copy the homepage business identity.
This section also needs homepage.css. Use the ordered dependency block below for this pattern in the Public starter; it includes responsive.css after homepage.css. Do not load Application styles here.
The source grid is three tracks on desktop, two below 1200px (photo spans both), and one below 768px. No component JavaScript is required.
HTML example Ready for the supplied page starter
HTML
Copy HTML
<!-- Paste inside Public starter <main>. Asset paths below target documentation/starters/. -->
<section aria-labelledby="features-title" class="wu-section bg-gold-50" id="features">
<div class="container wu-container">
<div class="wu-latest-feature-head">
<div>
<p class="wu-eyebrow">Made for your celebration</p>
<h2 class="wu-title" id="features-title">A thoughtful home for your event memories.</h2>
</div>
<div
class="d-xl-block d-md-flex justify-content-start justify-content-lg-between align-items-end"
>
<p class="wu-body">
Build a simple experience around the people who matter. These four sample features show
how existing cards form a complete section.
</p>
<div class="d-none d-md-block d-xl-none text-left mt-2">
<a class="wu-text-link" href="../../public/pricing.html#features">
Explore all features →
</a>
</div>
</div>
</div>
<div class="wu-latest-feature-grid">
<figure class="wu-latest-feature-photo">
<img
alt="Newlyweds celebrating with friends"
decoding="async"
height="698"
loading="lazy"
src="../../public/assets/images/memory-07.webp"
width="478"
/>
</figure>
<article class="wu-latest-feature-card">
<div class="wu-tile-icon">
<img class="text-gold-500" src="../../assets/icons/user.svg" alt="" />
</div>
<h3 class="fw-bold">Easy invitations</h3>
<p>Give friends one clear link before the celebration begins.</p>
</article>
<article class="wu-latest-feature-card">
<div class="wu-tile-icon">
<img class="text-gold-500" src="../../assets/icons/disc.svg" alt="" />
</div>
<h3 class="fw-bold">One shared collection</h3>
<p>Gather everyone’s favourite moments in a familiar layout.</p>
</article>
<article class="wu-latest-feature-card">
<div class="wu-tile-icon">
<img class="text-gold-500" src="../../assets/icons/picture.svg" alt="" />
</div>
<h3 class="fw-bold">Details that feel like you</h3>
<p>Keep your event information close to the photographs.</p>
</article>
<article class="wu-latest-feature-card">
<div class="wu-tile-icon">
<img class="text-gold-500" src="../../assets/icons/infinity.svg" alt="" />
</div>
<h3 class="fw-bold">Memories to revisit</h3>
<p>Return to the little moments you may have missed.</p>
</article>
</div>
<div class="d-block d-md-none d-xl-block text-left mt-2">
<a class="wu-text-link" href="../../public/pricing.html#features">Explore all features →</a>
</div>
</div>
</section>
CSS reference & dependencies
.wu-section.wu-container.wu-latest-feature-head.wu-eyebrow.wu-title.wu-body.wu-text-link.wu-latest-feature-grid.wu-latest-feature-photo.wu-latest-feature-card.wu-tile-icon
Stylesheets · in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css
public/assets/css/components.css
public/assets/css/public.css
public/assets/css/homepage.css
public/assets/css/site-shell.css
public/assets/css/responsive.css
assets/css/wu-icons.css
Scripts · once, in this order
No component JavaScript required.
The reference lists use project-root paths. The copyable dependency block and HTML below use paths relative to documentation/starters/, so they work in the delivered starter files. Load each dependency once; keep scripts after content. When moving your starter to public/ or application/, adjust those paths together. Keep its shell controller; a content-only preview does not need to reload it.
Dependencies
Copy Dependencies
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link href="../../public/assets/css/components.css" rel="stylesheet" />
<link href="../../public/assets/css/public.css" rel="stylesheet" />
<link href="../../public/assets/css/homepage.css" rel="stylesheet" />
<link href="../../public/assets/css/site-shell.css" rel="stylesheet" />
<link href="../../public/assets/css/responsive.css" rel="stylesheet" />
<link href="../../assets/css/wu-icons.css" rel="stylesheet" />
Documentation sample composition using existing source classes. Sample text, record IDs and demo-only hooks are local to this example.
Public · Media showcase
Source arrangement: public/index.html · .wu-section.wu-home-learn-dark > .container.wu-container > .wu-learn-grid
Insert inside the Public starter <main>. Repeat .wu-story-card inside .wu-learn-grid; keep the .wu-home-learn-dark parent for this source colour treatment.
Add class="wu-home-latest" to the Public starter body for the existing homepage section spacing. Keep a new data-page value such as new-public.html; do not copy the homepage business identity.
Use the ordered homepage dependency stack below in the Public starter. This is the same card family documented under Cards, arranged as a complete section.
Three columns collapse using the existing Public responsive rules. Source WebP media retain width/height, lazy loading, async decoding and the .wu-photo crop.
HTML example Ready for the supplied page starter
HTML
Copy HTML
<!-- Paste inside Public starter <main>. Asset paths below target documentation/starters/. -->
<section
aria-labelledby="docs-public-showcase-title"
class="wu-section wu-home-learn-dark"
id="docs-public-showcase"
>
<div class="container wu-container">
<div class="wu-section-head text-center">
<div>
<p class="wu-eyebrow wu-eyebrow--center">From the celebration</p>
<h2 class="wu-title-sans" id="docs-public-showcase-title">A few moments worth sharing.</h2>
</div>
</div>
<div class="wu-learn-grid">
<article class="wu-story-card">
<div class="wu-story-card-media wu-photo">
<img
alt="Friends gathering for a wedding photograph"
decoding="async"
height="645"
loading="lazy"
src="../../public/assets/images/memory-01.webp"
width="960"
/>
</div>
<div class="wu-story-card-copy">
<span class="wu-kicker">Before the ceremony</span>
<h2 class="wu-font-display">The people who made the day</h2>
<p class="my-3 text-neutral-500">
A gallery of laughter, anticipation and familiar faces.
</p>
<a class="wu-text-link dark" href="../../public/blog.html">Explore the story →</a>
</div>
</article>
<article class="wu-story-card">
<div class="wu-story-card-media wu-photo">
<img
alt="Newlyweds together outdoors"
decoding="async"
height="952"
loading="lazy"
src="../../public/assets/images/memory-04.webp"
width="833"
/>
</div>
<div class="wu-story-card-copy">
<span class="wu-kicker">After the vows</span>
<h2 class="wu-font-display">A moment just for two</h2>
<p class="my-3 text-neutral-500">
A quiet pause in the middle of a beautiful celebration.
</p>
<a class="wu-text-link dark" href="../../public/blog.html">Explore the story →</a>
</div>
</article>
<article class="wu-story-card">
<div class="wu-story-card-media wu-photo">
<img
alt="A celebration under sparklers"
decoding="async"
height="777"
loading="lazy"
src="../../public/assets/images/memory-08.webp"
width="762"
/>
</div>
<div class="wu-story-card-copy">
<span class="wu-kicker">The evening</span>
<h2 class="wu-font-display">One last dance together</h2>
<p class="my-3 text-neutral-500">
Candid photographs from the end of an unforgettable evening.
</p>
<a class="wu-text-link dark" href="../../public/blog.html">Explore the story →</a>
</div>
</article>
</div>
</div>
</section>
CSS reference & dependencies
.wu-section.wu-home-learn-dark.wu-container.wu-section-head.wu-eyebrow.wu-eyebrow--center.wu-title-sans.wu-learn-grid.wu-story-card.wu-story-card-media.wu-photo.wu-story-card-copy.wu-kicker.wu-font-display.wu-text-link
Stylesheets · in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css
public/assets/css/components.css
public/assets/css/public.css
public/assets/css/homepage.css
public/assets/css/site-shell.css
public/assets/css/responsive.css
assets/css/wu-icons.css
Scripts · once, in this order
No component JavaScript required.
The reference lists use project-root paths. The copyable dependency block and HTML below use paths relative to documentation/starters/, so they work in the delivered starter files. Load each dependency once; keep scripts after content. When moving your starter to public/ or application/, adjust those paths together. Keep its shell controller; a content-only preview does not need to reload it.
Dependencies
Copy Dependencies
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link href="../../public/assets/css/components.css" rel="stylesheet" />
<link href="../../public/assets/css/public.css" rel="stylesheet" />
<link href="../../public/assets/css/homepage.css" rel="stylesheet" />
<link href="../../public/assets/css/site-shell.css" rel="stylesheet" />
<link href="../../public/assets/css/responsive.css" rel="stylesheet" />
<link href="../../assets/css/wu-icons.css" rel="stylesheet" />
Documentation sample composition using existing source classes. Sample text, record IDs and demo-only hooks are local to this example.
Public · Call to action
Source arrangement: public/about.html · .wu-final.wu-final--cta
Insert directly inside the Public starter <main>. Copy .wu-final, .wu-final-inner, .wu-final-content and the action group together.
Uses the Public starter’s existing CSS and no component JavaScript. Source text alignment and action wrapping are kept for smaller screens.
The supporting paragraph reuses .wu-lead. All sample copy lives in Documentation; the About page is unchanged.
HTML example Ready for the supplied page starter
HTML
Copy HTML
<!-- Paste inside Public starter <main>. Asset paths below target documentation/starters/. -->
<section class="wu-final wu-final--cta" aria-labelledby="final-title">
<div class="wu-final-inner">
<div class="wu-final-content">
<p class="wu-eyebrow wu-eyebrow--center text-start text-sm-center text-gold-700">
Your next celebration
</p>
<h2 class="wu-title-sans text-start text-sm-center" id="final-title">
Make room for every guest’s memories.
</h2>
<p class="wu-lead text-start text-sm-center">
Share one album link before the event and give every photo a place to land.
</p>
<div class="wu-hero-actions justify-content-start justify-content-sm-center">
<a class="wu-button wu-button-lg wu-button--primary" href="../../public/create-album.html">
Start collecting →
</a>
<a class="wu-text-link" href="../../public/pricing.html">See pricing →</a>
</div>
</div>
</div>
</section>
CSS reference & dependencies
.wu-final.wu-final--cta.wu-final-inner.wu-final-content.wu-eyebrow.wu-eyebrow--center.wu-title-sans.wu-lead.wu-hero-actions.wu-button.wu-button-lg.wu-button--primary.wu-text-link
Stylesheets · in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css
public/assets/css/components.css
public/assets/css/pages.css
public/assets/css/responsive.css
public/assets/css/site-shell.css
public/assets/css/public-layout.css
public/assets/css/public.css
assets/css/wu-icons.css
Scripts · once, in this order
No component JavaScript required.
The reference lists use project-root paths. The copyable dependency block and HTML below use paths relative to documentation/starters/, so they work in the delivered starter files. Load each dependency once; keep scripts after content. When moving your starter to public/ or application/, adjust those paths together. Keep its shell controller; a content-only preview does not need to reload it.
Dependencies
Copy Dependencies
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link href="../../public/assets/css/components.css" rel="stylesheet" />
<link href="../../public/assets/css/pages.css" rel="stylesheet" />
<link href="../../public/assets/css/responsive.css" rel="stylesheet" />
<link href="../../public/assets/css/site-shell.css" rel="stylesheet" />
<link href="../../public/assets/css/public-layout.css" rel="stylesheet" />
<link href="../../public/assets/css/public.css" rel="stylesheet" />
<link href="../../assets/css/wu-icons.css" rel="stylesheet" />
Existing CTA example extended with sample copy and supporting text using .wu-lead; no new CTA styling.
Public · FAQ section
Source arrangement: public/index.html · #faq-preview > .container.wu-container > .wu-faq-layout
Insert inside the Public starter <main>. Keep id="faq-preview": homepage.css uses that ID to style this particular section. Use it once per page.
Add class="wu-home-latest" to the Public starter body for the existing homepage section spacing. Keep a new data-page value such as new-public.html; do not copy the homepage business identity.
This extends the existing FAQ component into a heading + question-list composition. Native details/summary provides keyboard and open/close behaviour; Bootstrap Collapse is not needed.
Use the homepage dependency stack below. The first answer starts open; remove open or change the sample questions as needed. Rename the heading ID and aria-labelledby together if composing multiple sections.
HTML example Ready for the supplied page starter
HTML
Copy HTML
<!-- Paste inside Public starter <main>. Asset paths below target documentation/starters/. -->
<section aria-labelledby="docs-faq-title" class="wu-section" id="faq-preview">
<div class="container wu-container">
<div class="wu-faq-layout">
<div class="wu-faq-intro mb-3 mb-sm-0">
<p class="wu-eyebrow">Frequently asked questions</p>
<h2 class="wu-title" id="docs-faq-title">Plan a little. Enjoy a lot.</h2>
<a class="d-none d-sm-inline-flex wu-text-link wu-faq-all" href="../../public/faq.html">
View all FAQs
<span aria-hidden="true">→</span>
</a>
</div>
<div class="wu-faq-list">
<details open>
<summary>When should we share our album link?</summary>
<div class="wu-faq-answer">
Add it to your invitation or welcome message so guests have it ready before the
celebration.
</div>
</details>
<details>
<summary>Can we add a reminder to the invitation?</summary>
<div class="wu-faq-answer">
Yes. Keep the message short and place the album link beside your event details.
</div>
</details>
<details>
<summary>What should we tell our guests?</summary>
<div class="wu-faq-answer">
Ask them to share the moments they love. A friendly sentence is usually enough.
</div>
</details>
</div>
<div class="d-block d-sm-none text-center mt-2">
<a class="wu-text-link text-neutral-900" href="../../public/faq.html">
View all FAQs
<span aria-hidden="true">→</span>
</a>
</div>
</div>
</div>
</section>
CSS reference & dependencies
.wu-section.wu-container.wu-faq-layout.wu-faq-intro.wu-eyebrow.wu-title.wu-text-link.wu-faq-all.wu-faq-list.wu-faq-answer
Stylesheets · in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css
public/assets/css/components.css
public/assets/css/public.css
public/assets/css/homepage.css
public/assets/css/site-shell.css
public/assets/css/responsive.css
assets/css/wu-icons.css
Scripts · once, in this order
No component JavaScript required.
The reference lists use project-root paths. The copyable dependency block and HTML below use paths relative to documentation/starters/, so they work in the delivered starter files. Load each dependency once; keep scripts after content. When moving your starter to public/ or application/, adjust those paths together. Keep its shell controller; a content-only preview does not need to reload it.
Dependencies
Copy Dependencies
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link href="../../public/assets/css/components.css" rel="stylesheet" />
<link href="../../public/assets/css/public.css" rel="stylesheet" />
<link href="../../public/assets/css/homepage.css" rel="stylesheet" />
<link href="../../public/assets/css/site-shell.css" rel="stylesheet" />
<link href="../../public/assets/css/responsive.css" rel="stylesheet" />
<link href="../../assets/css/wu-icons.css" rel="stylesheet" />
Documentation sample composition using existing source classes. Sample text, record IDs and demo-only hooks are local to this example.
Application · Form layout variations
Insert these cards inside main.wu-page, after its page header. They use shared form/card classes and Bootstrap layout utilities; the original Application shell stays around them.
Application · Single-column form
Source arrangement: application/album.html · application/contact.html · .wu-card > .wu-card-body > form; .form-control.wu-input; .form-control.wu-textarea
Paste this section inside the Application starter’s main.wu-page, after the page header. Keep body class="wu-application" and a new data-page value; these shared card/form classes do not need a page-specific body class.
The starter already loads the shared components, wu-form-controls.css and Application shell/feature CSS. Bootstrap grid and spacing utilities arrange the existing controls; no new form CSS is added.
Load the documentation-only layout-examples.js once to preview submit/reset feedback. Native required/email validation remains active. Replace the demo handler with your feature integration for production; no API, storage or success state is simulated.
HTML example Ready for the supplied page starter
HTML
Copy HTML
<!-- Paste inside Application starter main.wu-page (inside the existing shell). Asset paths below target documentation/starters/. -->
<section class="wu-card" aria-labelledby="docs-single-heading">
<div class="wu-card-head"><h2 id="docs-single-heading">Event information</h2></div>
<div class="wu-card-body">
<form class="d-grid gap-3" data-layout-form>
<div class="d-grid gap-2">
<label class="form-label wu-label mb-0" for="docs-single-title">Event title</label>
<input
class="form-control wu-input"
id="docs-single-title"
name="title"
type="text"
value="Alex & Jordan Celebration"
required
/>
</div>
<div class="d-grid gap-2">
<label class="form-label wu-label mb-0" for="docs-single-email">Contact email</label>
<input
class="form-control wu-input"
id="docs-single-email"
name="email"
type="email"
value="alex@example.com"
required
/>
</div>
<div class="d-grid gap-2">
<label class="form-label wu-label mb-0" for="docs-single-note">Welcome note</label>
<textarea class="form-control wu-textarea" id="docs-single-note" name="note" rows="3">We are so happy to celebrate with you. Share your favourite moments here.</textarea
>
</div>
<p class="wu-help mb-0" data-layout-status role="status" aria-live="polite">
Demo only — fields are editable; no information will be saved or sent.
</p>
<div class="d-flex flex-wrap gap-2">
<button class="wu-button wu-button-md wu-button--primary" type="submit">
Preview save
</button>
<button class="wu-button wu-button-md wu-button--outline" type="reset">
Reset example
</button>
</div>
</form>
</div>
</section>
CSS reference & dependencies
.wu-card.wu-card-head.wu-card-body.wu-label.wu-input.wu-textarea.wu-help.wu-button.wu-button-md.wu-button--primary.wu-button--outline
Stylesheets · in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css
assets/css/wu-icons.css
assets/css/wu-components.css
assets/css/wu-form-controls.css
application/assets/css/application-shell.css
application/assets/css/application-features.css
Scripts · once, in this order
documentation/assets/js/layout-examples.js
The reference lists use project-root paths. The copyable dependency block and HTML below use paths relative to documentation/starters/, so they work in the delivered starter files. Load each dependency once; keep scripts after content. When moving your starter to public/ or application/, adjust those paths together. Keep its shell controller; a content-only preview does not need to reload it.
Dependencies
Copy Dependencies
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link href="../../assets/css/wu-icons.css" rel="stylesheet" />
<link href="../../assets/css/wu-components.css" rel="stylesheet" />
<link href="../../assets/css/wu-form-controls.css" rel="stylesheet" />
<link href="../../application/assets/css/application-shell.css" rel="stylesheet" />
<link href="../../application/assets/css/application-features.css" rel="stylesheet" />
<script src="../assets/js/layout-examples.js"></script>
Documentation sample composition using existing source classes. Sample text, record IDs and demo-only hooks are local to this example.
Application · Two-column responsive form
Source arrangement: application/contact.html · application/premium.html · .wu-card; .row.g-3 > .col-12.col-md-6; .form-select.wu-select
Paste this section inside the Application starter’s main.wu-page, after the page header. Keep body class="wu-application" and a new data-page value; these shared card/form classes do not need a page-specific body class.
The starter already loads the shared components, wu-form-controls.css and Application shell/feature CSS. Bootstrap grid and spacing utilities arrange the existing controls; no new form CSS is added.
Load the documentation-only layout-examples.js once to preview submit/reset feedback. Native required/email validation remains active. Replace the demo handler with your feature integration for production; no API, storage or success state is simulated.
Fields use two columns at Bootstrap md (768px) and above, and one column below it. The full-width message and actions remain outside the two-column row.
HTML example Ready for the supplied page starter
HTML
Copy HTML
<!-- Paste inside Application starter main.wu-page (inside the existing shell). Asset paths below target documentation/starters/. -->
<section class="wu-card" aria-labelledby="docs-two-heading">
<div class="wu-card-head"><h2 id="docs-two-heading">Contact & event details</h2></div>
<div class="wu-card-body">
<form class="d-grid gap-3" data-layout-form>
<div class="row g-3">
<div class="col-12 col-md-6">
<div class="d-grid gap-2">
<label class="form-label wu-label mb-0" for="docs-two-firstName">First name</label>
<input
class="form-control wu-input"
id="docs-two-firstName"
name="firstName"
type="text"
value="Alex"
required
/>
</div>
</div>
<div class="col-12 col-md-6">
<div class="d-grid gap-2">
<label class="form-label wu-label mb-0" for="docs-two-lastName">Last name</label>
<input
class="form-control wu-input"
id="docs-two-lastName"
name="lastName"
type="text"
value="Morgan"
required
/>
</div>
</div>
<div class="col-12 col-md-6">
<div class="d-grid gap-2">
<label class="form-label wu-label mb-0" for="docs-two-email">Email address</label>
<input
class="form-control wu-input"
id="docs-two-email"
name="email"
type="email"
value="alex@example.com"
required
/>
</div>
</div>
<div class="col-12 col-md-6">
<div class="d-grid gap-2">
<label class="form-label wu-label mb-0" for="docs-two-eventType">Event type</label>
<select class="form-select wu-select" id="docs-two-eventType" name="eventType">
<option value="wedding">Wedding</option>
<option value="anniversary">Anniversary</option>
<option value="celebration">Celebration</option>
</select>
</div>
</div>
</div>
<div class="d-grid gap-2">
<label class="form-label wu-label mb-0" for="docs-two-message">Message for guests</label>
<textarea class="form-control wu-textarea" id="docs-two-message" name="message" rows="3">Bring your smiles. We will take care of the memories.</textarea
>
</div>
<p class="wu-help mb-0" data-layout-status role="status" aria-live="polite">
Demo only — fields are editable; no information will be saved or sent.
</p>
<div class="d-flex flex-wrap gap-2">
<button class="wu-button wu-button-md wu-button--primary" type="submit">
Preview save
</button>
<button class="wu-button wu-button-md wu-button--outline" type="reset">
Reset example
</button>
</div>
</form>
</div>
</section>
CSS reference & dependencies
.wu-card.wu-card-head.wu-card-body.wu-label.wu-input.wu-select.wu-textarea.wu-help.wu-button.wu-button-md.wu-button--primary.wu-button--outline
Stylesheets · in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css
assets/css/wu-icons.css
assets/css/wu-components.css
assets/css/wu-form-controls.css
application/assets/css/application-shell.css
application/assets/css/application-features.css
Scripts · once, in this order
documentation/assets/js/layout-examples.js
The reference lists use project-root paths. The copyable dependency block and HTML below use paths relative to documentation/starters/, so they work in the delivered starter files. Load each dependency once; keep scripts after content. When moving your starter to public/ or application/, adjust those paths together. Keep its shell controller; a content-only preview does not need to reload it.
Dependencies
Copy Dependencies
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link href="../../assets/css/wu-icons.css" rel="stylesheet" />
<link href="../../assets/css/wu-components.css" rel="stylesheet" />
<link href="../../assets/css/wu-form-controls.css" rel="stylesheet" />
<link href="../../application/assets/css/application-shell.css" rel="stylesheet" />
<link href="../../application/assets/css/application-features.css" rel="stylesheet" />
<script src="../assets/js/layout-examples.js"></script>
Documentation sample composition using existing source classes. Sample text, record IDs and demo-only hooks are local to this example.
Application · Grouped form & actions
Source arrangement: application/album.html · .wu-card; fieldset; .row.g-3; .form-check; .form-switch.wu-form-switch
Paste this section inside the Application starter’s main.wu-page, after the page header. Keep body class="wu-application" and a new data-page value; these shared card/form classes do not need a page-specific body class.
The starter already loads the shared components, wu-form-controls.css and Application shell/feature CSS. Bootstrap grid and spacing utilities arrange the existing controls; no new form CSS is added.
Load the documentation-only layout-examples.js once to preview submit/reset feedback. Native required/email validation remains active. Replace the demo handler with your feature integration for production; no API, storage or success state is simulated.
Fieldsets group related fields. Keep radio names equal within one group and IDs unique. The source switch remains a native checkbox with role="switch".
HTML example Ready for the supplied page starter
HTML
Copy HTML
<!-- Paste inside Application starter main.wu-page (inside the existing shell). Asset paths below target documentation/starters/. -->
<section class="wu-card" aria-labelledby="docs-group-heading">
<div class="wu-card-head"><h2 id="docs-group-heading">Event & guest preferences</h2></div>
<div class="wu-card-body">
<form class="d-grid gap-3" data-layout-form>
<fieldset class="border-0 p-0 m-0">
<legend class="h6 fw-bold text-bronze-600 mb-3">Event details</legend>
<div class="row g-3">
<div class="col-12 col-lg-6">
<div class="d-grid gap-2">
<label class="form-label wu-label mb-0" for="docs-group-title">Event title</label>
<input
class="form-control wu-input"
id="docs-group-title"
name="title"
type="text"
value="Alex & Jordan Celebration"
required
/>
</div>
</div>
<div class="col-12 col-lg-6">
<div class="d-grid gap-2">
<label class="form-label wu-label mb-0" for="docs-group-date">Event date</label>
<input
class="form-control wu-input"
id="docs-group-date"
name="date"
type="date"
value="2027-06-12"
required
/>
</div>
</div>
</div>
</fieldset>
<fieldset class="border-0 p-0 m-0">
<legend class="h6 fw-bold text-bronze-600 mb-3">Guest preferences</legend>
<div class="form-check form-switch wu-form-switch mb-3">
<input
class="form-check-input"
type="checkbox"
role="switch"
name="public"
id="docs-group-public"
checked
/>
<label class="form-check-label" for="docs-group-public">
Show uploaded photos to guests
</label>
</div>
<div class="form-check mb-3">
<input
class="form-check-input"
type="checkbox"
name="guestbook"
id="docs-group-guestbook"
checked
/>
<label class="form-check-label" for="docs-group-guestbook">
Invite guests to leave a message
</label>
</div>
<p class="wu-label mb-2" id="docs-group-reminder-label">Reminder preference</p>
<div
role="radiogroup"
aria-labelledby="docs-group-reminder-label"
class="d-flex flex-wrap gap-3"
>
<div class="form-check">
<input
class="form-check-input"
type="radio"
name="docs-group-reminder"
value="email"
id="docs-group-email"
checked
/>
<label class="form-check-label" for="docs-group-email">Email reminder</label>
</div>
<div class="form-check">
<input
class="form-check-input"
type="radio"
name="docs-group-reminder"
value="none"
id="docs-group-none"
/>
<label class="form-check-label" for="docs-group-none">No reminder</label>
</div>
</div>
</fieldset>
<p class="wu-help mb-0" data-layout-status role="status" aria-live="polite">
Demo only — fields are editable; no information will be saved or sent.
</p>
<div class="d-flex flex-wrap gap-2">
<button class="wu-button wu-button-md wu-button--primary" type="submit">
Preview save
</button>
<button class="wu-button wu-button-md wu-button--outline" type="reset">
Reset example
</button>
</div>
</form>
</div>
</section>
CSS reference & dependencies
.wu-card.wu-card-head.wu-card-body.wu-label.wu-input.wu-form-switch.wu-help.wu-button.wu-button-md.wu-button--primary.wu-button--outline
Stylesheets · in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css
assets/css/wu-icons.css
assets/css/wu-components.css
assets/css/wu-form-controls.css
application/assets/css/application-shell.css
application/assets/css/application-features.css
Scripts · once, in this order
documentation/assets/js/layout-examples.js
The reference lists use project-root paths. The copyable dependency block and HTML below use paths relative to documentation/starters/, so they work in the delivered starter files. Load each dependency once; keep scripts after content. When moving your starter to public/ or application/, adjust those paths together. Keep its shell controller; a content-only preview does not need to reload it.
Dependencies
Copy Dependencies
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link href="../../assets/css/wu-icons.css" rel="stylesheet" />
<link href="../../assets/css/wu-components.css" rel="stylesheet" />
<link href="../../assets/css/wu-form-controls.css" rel="stylesheet" />
<link href="../../application/assets/css/application-shell.css" rel="stylesheet" />
<link href="../../application/assets/css/application-features.css" rel="stylesheet" />
<script src="../assets/js/layout-examples.js"></script>
Documentation sample composition using existing source classes. Sample text, record IDs and demo-only hooks are local to this example.
Application · Records & repeated content
These two layouts need different source body scopes. The notes show which class and CSS belong to each; they are intentionally previewed separately.
Application · Data table with actions
Source arrangement: application/dashboard.html · .wu-card > .wu-toolbar + .wu-table-wrap; .wu-table; .wu-mobile-albums; .wu-pagination
Paste inside the Application starter main.wu-page. Add wu-page-dashboard to the body class for these existing responsive table rules, while keeping data-page="new-page". Keep the starter shell and dependencies.
Desktop/tablet uses the source table with horizontal overflow from 768px; the source CSS hides Visibility below its breakpoint. Below 768px the paired .wu-mobile-albums list replaces the table. Keep both representations in sync; flex-column is a Bootstrap utility that stacks repeated mobile items.
Search, visibility filter, two-page pagination and no-results feedback operate only on these six static sample records. Each table/mobile pair shares its data-layout-record key.
Actions use the existing Bootstrap dropdown/modal patterns and only describe the requested demo action. Include the related dialog. Business IDs such as albumRows and product data-album-index hooks are intentionally absent so application.js cannot overwrite the example.
Load layout-examples.js once after Bootstrap. These data-layout-* hooks are documentation-only; replace them with your feature controller when connecting real records. No changes are persisted.
Place the related dialog blocks after .wu-app, before </body>, as in the Application starter. Keep each dialog ID unique when composing examples.
HTML example Ready for the supplied page starter
HTML
Copy HTML
<!-- Paste inside Application starter main.wu-page (inside the existing shell). Asset paths below target documentation/starters/. -->
<section class="wu-card" data-layout-table aria-labelledby="docs-table-title">
<div class="wu-card-head">
<h2 id="docs-table-title">Event albums</h2>
<span class="wu-count-badge" data-layout-total>6 sample albums</span>
</div>
<div class="wu-toolbar">
<div class="wu-toolbar-left">
<select
class="form-select wu-select w-50"
data-layout-filter
aria-label="Filter sample albums by visibility"
>
<option value="all">All visibility</option>
<option value="public">Public</option>
<option value="private">Private</option>
</select>
<div class="wu-search w-100">
<i class="wu-icon wu-icon--search-gold wu-icon--sm" aria-hidden="true"></i>
<input
class="form-control wu-input"
type="search"
placeholder="Search sample albums"
aria-label="Search sample albums"
data-layout-search
/>
</div>
</div>
</div>
<div class="wu-card-body pt-0 pb-0">
<p class="wu-help" data-layout-status role="status" aria-live="polite">
Sample records only. View, Edit and Delete open a demo dialog; they never update these
records.
</p>
</div>
<div class="wu-table-wrap">
<table class="wu-table">
<thead>
<tr>
<th scope="col">Album</th>
<th scope="col">QR Code</th>
<th scope="col">Guest Features</th>
<th scope="col">Visibility</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody>
<tr
data-layout-record="alex-jordan"
data-layout-search-text="Alex & Jordan alex-jordan"
data-layout-state="public"
>
<td>
<div class="wu-album-cell">
<div class="wu-thumb">
<img
src="../../public/assets/images/memory-04.webp"
alt=""
width="64"
height="64"
loading="lazy"
decoding="async"
/>
</div>
<div>
<div class="wu-album-name">Alex & Jordan</div>
<div class="wu-album-folder">Drive Folder: alex-jordan</div>
<div class="wu-album-date">12 Jun 2027</div>
</div>
</div>
</td>
<td>
<button
class="wu-album-qr"
type="button"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="View QR"
data-layout-label="Alex & Jordan"
aria-label="Preview QR action for Alex & Jordan"
>
<img src="../../application/assets/images/qr.svg" alt="" width="64" height="64" />
<span class="mt-2">View QR</span>
</button>
</td>
<td>
<div class="d-flex flex-wrap gap-2">
<span class="badge wu-badge">Guestbook</span>
<span class="badge wu-badge">Voicemail</span>
</div>
</td>
<td><span class="badge wu-badge wu-badge--primary-fill">Public</span></td>
<td>
<div class="wu-row-actions">
<div class="wu-action-menu dropdown">
<button
class="wu-button wu-button--outline wu-button-sm"
type="button"
data-bs-toggle="dropdown"
aria-expanded="false"
data-bs-config='{"popperConfig":{"strategy":"fixed"}}'
>
Actions
<i class="wu-icon wu-icon--chevron-down wu-icon--xs" aria-hidden="true"></i>
<span class="visually-hidden">for Alex & Jordan</span>
</button>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<button
type="button"
class="dropdown-item"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="View"
data-layout-label="Alex & Jordan"
>
View
</button>
</li>
<li>
<button
type="button"
class="dropdown-item"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="Edit"
data-layout-label="Alex & Jordan"
>
Edit
</button>
</li>
<li>
<button
type="button"
class="dropdown-item text-danger-500"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="Delete"
data-layout-label="Alex & Jordan"
>
Delete
</button>
</li>
</ul>
</div>
</div>
</td>
</tr>
<tr
data-layout-record="maya-sam"
data-layout-search-text="Maya & Sam maya-sam"
data-layout-state="private"
>
<td>
<div class="wu-album-cell">
<div class="wu-thumb">
<img
src="../../public/assets/images/memory-10.webp"
alt=""
width="64"
height="64"
loading="lazy"
decoding="async"
/>
</div>
<div>
<div class="wu-album-name">Maya & Sam</div>
<div class="wu-album-folder">Drive Folder: maya-sam</div>
<div class="wu-album-date">19 Jun 2027</div>
</div>
</div>
</td>
<td>
<button
class="wu-album-qr"
type="button"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="View QR"
data-layout-label="Maya & Sam"
aria-label="Preview QR action for Maya & Sam"
>
<img src="../../application/assets/images/qr.svg" alt="" width="64" height="64" />
<span class="mt-2">View QR</span>
</button>
</td>
<td>
<div class="d-flex flex-wrap gap-2">
<span class="badge wu-badge">Guestbook</span>
<span class="badge wu-badge">Voicemail</span>
</div>
</td>
<td><span class="badge wu-badge">Private</span></td>
<td>
<div class="wu-row-actions">
<div class="wu-action-menu dropdown">
<button
class="wu-button wu-button--outline wu-button-sm"
type="button"
data-bs-toggle="dropdown"
aria-expanded="false"
data-bs-config='{"popperConfig":{"strategy":"fixed"}}'
>
Actions
<i class="wu-icon wu-icon--chevron-down wu-icon--xs" aria-hidden="true"></i>
<span class="visually-hidden">for Maya & Sam</span>
</button>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<button
type="button"
class="dropdown-item"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="View"
data-layout-label="Maya & Sam"
>
View
</button>
</li>
<li>
<button
type="button"
class="dropdown-item"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="Edit"
data-layout-label="Maya & Sam"
>
Edit
</button>
</li>
<li>
<button
type="button"
class="dropdown-item text-danger-500"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="Delete"
data-layout-label="Maya & Sam"
>
Delete
</button>
</li>
</ul>
</div>
</div>
</td>
</tr>
<tr
data-layout-record="nora-jamie"
data-layout-search-text="Nora & Jamie nora-jamie"
data-layout-state="public"
>
<td>
<div class="wu-album-cell">
<div class="wu-thumb">
<img
src="../../public/assets/images/memory-08.webp"
alt=""
width="64"
height="64"
loading="lazy"
decoding="async"
/>
</div>
<div>
<div class="wu-album-name">Nora & Jamie</div>
<div class="wu-album-folder">Drive Folder: nora-jamie</div>
<div class="wu-album-date">26 Jun 2027</div>
</div>
</div>
</td>
<td>
<button
class="wu-album-qr"
type="button"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="View QR"
data-layout-label="Nora & Jamie"
aria-label="Preview QR action for Nora & Jamie"
>
<img src="../../application/assets/images/qr.svg" alt="" width="64" height="64" />
<span class="mt-2">View QR</span>
</button>
</td>
<td>
<div class="d-flex flex-wrap gap-2">
<span class="badge wu-badge">Guestbook</span>
<span class="badge wu-badge">Voicemail</span>
</div>
</td>
<td><span class="badge wu-badge wu-badge--primary-fill">Public</span></td>
<td>
<div class="wu-row-actions">
<div class="wu-action-menu dropdown">
<button
class="wu-button wu-button--outline wu-button-sm"
type="button"
data-bs-toggle="dropdown"
aria-expanded="false"
data-bs-config='{"popperConfig":{"strategy":"fixed"}}'
>
Actions
<i class="wu-icon wu-icon--chevron-down wu-icon--xs" aria-hidden="true"></i>
<span class="visually-hidden">for Nora & Jamie</span>
</button>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<button
type="button"
class="dropdown-item"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="View"
data-layout-label="Nora & Jamie"
>
View
</button>
</li>
<li>
<button
type="button"
class="dropdown-item"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="Edit"
data-layout-label="Nora & Jamie"
>
Edit
</button>
</li>
<li>
<button
type="button"
class="dropdown-item text-danger-500"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="Delete"
data-layout-label="Nora & Jamie"
>
Delete
</button>
</li>
</ul>
</div>
</div>
</td>
</tr>
<tr
data-layout-record="riley-casey"
data-layout-search-text="Riley & Casey riley-casey"
data-layout-state="private"
hidden
class="d-none"
>
<td>
<div class="wu-album-cell">
<div class="wu-thumb">
<img
src="../../public/assets/images/memory-02.webp"
alt=""
width="64"
height="64"
loading="lazy"
decoding="async"
/>
</div>
<div>
<div class="wu-album-name">Riley & Casey</div>
<div class="wu-album-folder">Drive Folder: riley-casey</div>
<div class="wu-album-date">03 Jul 2027</div>
</div>
</div>
</td>
<td>
<button
class="wu-album-qr"
type="button"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="View QR"
data-layout-label="Riley & Casey"
aria-label="Preview QR action for Riley & Casey"
>
<img src="../../application/assets/images/qr.svg" alt="" width="64" height="64" />
<span class="mt-2">View QR</span>
</button>
</td>
<td>
<div class="d-flex flex-wrap gap-2">
<span class="badge wu-badge">Guestbook</span>
<span class="badge wu-badge">Voicemail</span>
</div>
</td>
<td><span class="badge wu-badge">Private</span></td>
<td>
<div class="wu-row-actions">
<div class="wu-action-menu dropdown">
<button
class="wu-button wu-button--outline wu-button-sm"
type="button"
data-bs-toggle="dropdown"
aria-expanded="false"
data-bs-config='{"popperConfig":{"strategy":"fixed"}}'
>
Actions
<i class="wu-icon wu-icon--chevron-down wu-icon--xs" aria-hidden="true"></i>
<span class="visually-hidden">for Riley & Casey</span>
</button>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<button
type="button"
class="dropdown-item"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="View"
data-layout-label="Riley & Casey"
>
View
</button>
</li>
<li>
<button
type="button"
class="dropdown-item"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="Edit"
data-layout-label="Riley & Casey"
>
Edit
</button>
</li>
<li>
<button
type="button"
class="dropdown-item text-danger-500"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="Delete"
data-layout-label="Riley & Casey"
>
Delete
</button>
</li>
</ul>
</div>
</div>
</td>
</tr>
<tr
data-layout-record="ellis-robin"
data-layout-search-text="Ellis & Robin ellis-robin"
data-layout-state="public"
hidden
class="d-none"
>
<td>
<div class="wu-album-cell">
<div class="wu-thumb">
<img
src="../../public/assets/images/memory-05.webp"
alt=""
width="64"
height="64"
loading="lazy"
decoding="async"
/>
</div>
<div>
<div class="wu-album-name">Ellis & Robin</div>
<div class="wu-album-folder">Drive Folder: ellis-robin</div>
<div class="wu-album-date">10 Jul 2027</div>
</div>
</div>
</td>
<td>
<button
class="wu-album-qr"
type="button"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="View QR"
data-layout-label="Ellis & Robin"
aria-label="Preview QR action for Ellis & Robin"
>
<img src="../../application/assets/images/qr.svg" alt="" width="64" height="64" />
<span class="mt-2">View QR</span>
</button>
</td>
<td>
<div class="d-flex flex-wrap gap-2">
<span class="badge wu-badge">Guestbook</span>
<span class="badge wu-badge">Voicemail</span>
</div>
</td>
<td><span class="badge wu-badge wu-badge--primary-fill">Public</span></td>
<td>
<div class="wu-row-actions">
<div class="wu-action-menu dropdown">
<button
class="wu-button wu-button--outline wu-button-sm"
type="button"
data-bs-toggle="dropdown"
aria-expanded="false"
data-bs-config='{"popperConfig":{"strategy":"fixed"}}'
>
Actions
<i class="wu-icon wu-icon--chevron-down wu-icon--xs" aria-hidden="true"></i>
<span class="visually-hidden">for Ellis & Robin</span>
</button>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<button
type="button"
class="dropdown-item"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="View"
data-layout-label="Ellis & Robin"
>
View
</button>
</li>
<li>
<button
type="button"
class="dropdown-item"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="Edit"
data-layout-label="Ellis & Robin"
>
Edit
</button>
</li>
<li>
<button
type="button"
class="dropdown-item text-danger-500"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="Delete"
data-layout-label="Ellis & Robin"
>
Delete
</button>
</li>
</ul>
</div>
</div>
</td>
</tr>
<tr
data-layout-record="lena-drew"
data-layout-search-text="Lena & Drew lena-drew"
data-layout-state="public"
hidden
class="d-none"
>
<td>
<div class="wu-album-cell">
<div class="wu-thumb">
<img
src="../../public/assets/images/memory-03.webp"
alt=""
width="64"
height="64"
loading="lazy"
decoding="async"
/>
</div>
<div>
<div class="wu-album-name">Lena & Drew</div>
<div class="wu-album-folder">Drive Folder: lena-drew</div>
<div class="wu-album-date">17 Jul 2027</div>
</div>
</div>
</td>
<td>
<button
class="wu-album-qr"
type="button"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="View QR"
data-layout-label="Lena & Drew"
aria-label="Preview QR action for Lena & Drew"
>
<img src="../../application/assets/images/qr.svg" alt="" width="64" height="64" />
<span class="mt-2">View QR</span>
</button>
</td>
<td>
<div class="d-flex flex-wrap gap-2">
<span class="badge wu-badge">Guestbook</span>
<span class="badge wu-badge">Voicemail</span>
</div>
</td>
<td><span class="badge wu-badge wu-badge--primary-fill">Public</span></td>
<td>
<div class="wu-row-actions">
<div class="wu-action-menu dropdown">
<button
class="wu-button wu-button--outline wu-button-sm"
type="button"
data-bs-toggle="dropdown"
aria-expanded="false"
data-bs-config='{"popperConfig":{"strategy":"fixed"}}'
>
Actions
<i class="wu-icon wu-icon--chevron-down wu-icon--xs" aria-hidden="true"></i>
<span class="visually-hidden">for Lena & Drew</span>
</button>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<button
type="button"
class="dropdown-item"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="View"
data-layout-label="Lena & Drew"
>
View
</button>
</li>
<li>
<button
type="button"
class="dropdown-item"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="Edit"
data-layout-label="Lena & Drew"
>
Edit
</button>
</li>
<li>
<button
type="button"
class="dropdown-item text-danger-500"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="Delete"
data-layout-label="Lena & Drew"
>
Delete
</button>
</li>
</ul>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div class="wu-mobile-albums flex-column">
<article
data-layout-record="alex-jordan"
data-layout-search-text="Alex & Jordan alex-jordan"
data-layout-state="public"
class="wu-mobile-album"
>
<div class="wu-mobile-album-top">
<div class="wu-album-cell">
<div class="wu-thumb">
<img
src="../../public/assets/images/memory-04.webp"
alt=""
width="64"
height="64"
loading="lazy"
decoding="async"
/>
</div>
<div>
<div class="wu-album-name">Alex & Jordan</div>
<div class="wu-album-folder">Drive Folder: alex-jordan</div>
<div class="wu-album-date">12 Jun 2027</div>
</div>
</div>
</div>
<div class="wu-mobile-album-meta">
<span class="badge wu-badge wu-badge--primary-fill">Public</span>
<span>Guestbook · Voicemail</span>
</div>
<div class="wu-mobile-album-actions">
<div class="wu-action-menu dropdown">
<button
class="wu-button wu-button--outline wu-button-sm"
type="button"
data-bs-toggle="dropdown"
aria-expanded="false"
data-bs-config='{"popperConfig":{"strategy":"fixed"}}'
>
Actions
<i class="wu-icon wu-icon--chevron-down wu-icon--xs" aria-hidden="true"></i>
<span class="visually-hidden">for Alex & Jordan</span>
</button>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<button
type="button"
class="dropdown-item"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="View"
data-layout-label="Alex & Jordan"
>
View
</button>
</li>
<li>
<button
type="button"
class="dropdown-item"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="Edit"
data-layout-label="Alex & Jordan"
>
Edit
</button>
</li>
<li>
<button
type="button"
class="dropdown-item text-danger-500"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="Delete"
data-layout-label="Alex & Jordan"
>
Delete
</button>
</li>
</ul>
</div>
</div>
</article>
<article
data-layout-record="maya-sam"
data-layout-search-text="Maya & Sam maya-sam"
data-layout-state="private"
class="wu-mobile-album"
>
<div class="wu-mobile-album-top">
<div class="wu-album-cell">
<div class="wu-thumb">
<img
src="../../public/assets/images/memory-10.webp"
alt=""
width="64"
height="64"
loading="lazy"
decoding="async"
/>
</div>
<div>
<div class="wu-album-name">Maya & Sam</div>
<div class="wu-album-folder">Drive Folder: maya-sam</div>
<div class="wu-album-date">19 Jun 2027</div>
</div>
</div>
</div>
<div class="wu-mobile-album-meta">
<span class="badge wu-badge">Private</span>
<span>Guestbook · Voicemail</span>
</div>
<div class="wu-mobile-album-actions">
<div class="wu-action-menu dropdown">
<button
class="wu-button wu-button--outline wu-button-sm"
type="button"
data-bs-toggle="dropdown"
aria-expanded="false"
data-bs-config='{"popperConfig":{"strategy":"fixed"}}'
>
Actions
<i class="wu-icon wu-icon--chevron-down wu-icon--xs" aria-hidden="true"></i>
<span class="visually-hidden">for Maya & Sam</span>
</button>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<button
type="button"
class="dropdown-item"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="View"
data-layout-label="Maya & Sam"
>
View
</button>
</li>
<li>
<button
type="button"
class="dropdown-item"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="Edit"
data-layout-label="Maya & Sam"
>
Edit
</button>
</li>
<li>
<button
type="button"
class="dropdown-item text-danger-500"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="Delete"
data-layout-label="Maya & Sam"
>
Delete
</button>
</li>
</ul>
</div>
</div>
</article>
<article
data-layout-record="nora-jamie"
data-layout-search-text="Nora & Jamie nora-jamie"
data-layout-state="public"
class="wu-mobile-album"
>
<div class="wu-mobile-album-top">
<div class="wu-album-cell">
<div class="wu-thumb">
<img
src="../../public/assets/images/memory-08.webp"
alt=""
width="64"
height="64"
loading="lazy"
decoding="async"
/>
</div>
<div>
<div class="wu-album-name">Nora & Jamie</div>
<div class="wu-album-folder">Drive Folder: nora-jamie</div>
<div class="wu-album-date">26 Jun 2027</div>
</div>
</div>
</div>
<div class="wu-mobile-album-meta">
<span class="badge wu-badge wu-badge--primary-fill">Public</span>
<span>Guestbook · Voicemail</span>
</div>
<div class="wu-mobile-album-actions">
<div class="wu-action-menu dropdown">
<button
class="wu-button wu-button--outline wu-button-sm"
type="button"
data-bs-toggle="dropdown"
aria-expanded="false"
data-bs-config='{"popperConfig":{"strategy":"fixed"}}'
>
Actions
<i class="wu-icon wu-icon--chevron-down wu-icon--xs" aria-hidden="true"></i>
<span class="visually-hidden">for Nora & Jamie</span>
</button>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<button
type="button"
class="dropdown-item"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="View"
data-layout-label="Nora & Jamie"
>
View
</button>
</li>
<li>
<button
type="button"
class="dropdown-item"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="Edit"
data-layout-label="Nora & Jamie"
>
Edit
</button>
</li>
<li>
<button
type="button"
class="dropdown-item text-danger-500"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="Delete"
data-layout-label="Nora & Jamie"
>
Delete
</button>
</li>
</ul>
</div>
</div>
</article>
<article
data-layout-record="riley-casey"
data-layout-search-text="Riley & Casey riley-casey"
data-layout-state="private"
class="wu-mobile-album d-none"
hidden
>
<div class="wu-mobile-album-top">
<div class="wu-album-cell">
<div class="wu-thumb">
<img
src="../../public/assets/images/memory-02.webp"
alt=""
width="64"
height="64"
loading="lazy"
decoding="async"
/>
</div>
<div>
<div class="wu-album-name">Riley & Casey</div>
<div class="wu-album-folder">Drive Folder: riley-casey</div>
<div class="wu-album-date">03 Jul 2027</div>
</div>
</div>
</div>
<div class="wu-mobile-album-meta">
<span class="badge wu-badge">Private</span>
<span>Guestbook · Voicemail</span>
</div>
<div class="wu-mobile-album-actions">
<div class="wu-action-menu dropdown">
<button
class="wu-button wu-button--outline wu-button-sm"
type="button"
data-bs-toggle="dropdown"
aria-expanded="false"
data-bs-config='{"popperConfig":{"strategy":"fixed"}}'
>
Actions
<i class="wu-icon wu-icon--chevron-down wu-icon--xs" aria-hidden="true"></i>
<span class="visually-hidden">for Riley & Casey</span>
</button>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<button
type="button"
class="dropdown-item"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="View"
data-layout-label="Riley & Casey"
>
View
</button>
</li>
<li>
<button
type="button"
class="dropdown-item"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="Edit"
data-layout-label="Riley & Casey"
>
Edit
</button>
</li>
<li>
<button
type="button"
class="dropdown-item text-danger-500"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="Delete"
data-layout-label="Riley & Casey"
>
Delete
</button>
</li>
</ul>
</div>
</div>
</article>
<article
data-layout-record="ellis-robin"
data-layout-search-text="Ellis & Robin ellis-robin"
data-layout-state="public"
class="wu-mobile-album d-none"
hidden
>
<div class="wu-mobile-album-top">
<div class="wu-album-cell">
<div class="wu-thumb">
<img
src="../../public/assets/images/memory-05.webp"
alt=""
width="64"
height="64"
loading="lazy"
decoding="async"
/>
</div>
<div>
<div class="wu-album-name">Ellis & Robin</div>
<div class="wu-album-folder">Drive Folder: ellis-robin</div>
<div class="wu-album-date">10 Jul 2027</div>
</div>
</div>
</div>
<div class="wu-mobile-album-meta">
<span class="badge wu-badge wu-badge--primary-fill">Public</span>
<span>Guestbook · Voicemail</span>
</div>
<div class="wu-mobile-album-actions">
<div class="wu-action-menu dropdown">
<button
class="wu-button wu-button--outline wu-button-sm"
type="button"
data-bs-toggle="dropdown"
aria-expanded="false"
data-bs-config='{"popperConfig":{"strategy":"fixed"}}'
>
Actions
<i class="wu-icon wu-icon--chevron-down wu-icon--xs" aria-hidden="true"></i>
<span class="visually-hidden">for Ellis & Robin</span>
</button>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<button
type="button"
class="dropdown-item"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="View"
data-layout-label="Ellis & Robin"
>
View
</button>
</li>
<li>
<button
type="button"
class="dropdown-item"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="Edit"
data-layout-label="Ellis & Robin"
>
Edit
</button>
</li>
<li>
<button
type="button"
class="dropdown-item text-danger-500"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="Delete"
data-layout-label="Ellis & Robin"
>
Delete
</button>
</li>
</ul>
</div>
</div>
</article>
<article
data-layout-record="lena-drew"
data-layout-search-text="Lena & Drew lena-drew"
data-layout-state="public"
class="wu-mobile-album d-none"
hidden
>
<div class="wu-mobile-album-top">
<div class="wu-album-cell">
<div class="wu-thumb">
<img
src="../../public/assets/images/memory-03.webp"
alt=""
width="64"
height="64"
loading="lazy"
decoding="async"
/>
</div>
<div>
<div class="wu-album-name">Lena & Drew</div>
<div class="wu-album-folder">Drive Folder: lena-drew</div>
<div class="wu-album-date">17 Jul 2027</div>
</div>
</div>
</div>
<div class="wu-mobile-album-meta">
<span class="badge wu-badge wu-badge--primary-fill">Public</span>
<span>Guestbook · Voicemail</span>
</div>
<div class="wu-mobile-album-actions">
<div class="wu-action-menu dropdown">
<button
class="wu-button wu-button--outline wu-button-sm"
type="button"
data-bs-toggle="dropdown"
aria-expanded="false"
data-bs-config='{"popperConfig":{"strategy":"fixed"}}'
>
Actions
<i class="wu-icon wu-icon--chevron-down wu-icon--xs" aria-hidden="true"></i>
<span class="visually-hidden">for Lena & Drew</span>
</button>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<button
type="button"
class="dropdown-item"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="View"
data-layout-label="Lena & Drew"
>
View
</button>
</li>
<li>
<button
type="button"
class="dropdown-item"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="Edit"
data-layout-label="Lena & Drew"
>
Edit
</button>
</li>
<li>
<button
type="button"
class="dropdown-item text-danger-500"
data-bs-toggle="modal"
data-bs-target="#docs-table-action"
data-layout-action="Delete"
data-layout-label="Lena & Drew"
>
Delete
</button>
</li>
</ul>
</div>
</div>
</article>
</div>
<p class="wu-help p-3 mb-0 d-none" data-layout-empty hidden>
No sample albums match. Clear the search or choose All visibility.
</p>
<div class="wu-pagination">
<p class="text-neutral-700 mb-0 d-none d-sm-block" data-layout-range>Showing 1–3 of 6</p>
<nav aria-label="Sample album pages">
<ul class="pagination justify-content-center mb-0">
<li class="page-item disabled">
<button class="page-link" type="button" data-layout-page="previous" disabled>
Previous
</button>
</li>
<li class="page-item">
<button class="page-link active" type="button" data-layout-page="1" aria-current="page">
1
</button>
</li>
<li class="page-item">
<button class="page-link" type="button" data-layout-page="2">2</button>
</li>
<li class="page-item">
<button class="page-link" type="button" data-layout-page="next">Next</button>
</li>
</ul>
</nav>
</div>
</section>
<!-- Related Bootstrap dialogs: place after .wu-app, before </body>; include once. -->
<div
class="wu-modal modal fade"
id="docs-table-action"
tabindex="-1"
aria-labelledby="docs-table-action-title"
aria-describedby="docs-table-action-message"
data-layout-action-dialog
>
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="wu-modal-head modal-header">
<h2 class="text-bronze-600 fw-bold" id="docs-table-action-title">Demo action</h2>
<button class="btn-close" type="button" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="wu-modal-body modal-body">
<p class="mb-0" id="docs-table-action-message" data-layout-action-message>
This example does not change records.
</p>
</div>
<div class="wu-modal-foot modal-footer">
<button
class="wu-button wu-button-md wu-button--outline"
type="button"
data-bs-dismiss="modal"
>
Close demo
</button>
</div>
</div>
</div>
</div>
CSS reference & dependencies
.wu-card.wu-card-head.wu-count-badge.wu-toolbar.wu-toolbar-left.wu-select.wu-search.wu-icon.wu-icon--search-gold.wu-icon--sm.wu-input.wu-card-body.wu-help.wu-table-wrap.wu-table.wu-album-cell.wu-thumb.wu-album-name.wu-album-folder.wu-album-date.wu-album-qr.wu-badge.wu-badge--primary-fill.wu-row-actions.wu-action-menu.wu-button.wu-button--outline.wu-button-sm.wu-icon--chevron-down.wu-icon--xs.wu-mobile-albums.wu-mobile-album.wu-mobile-album-top.wu-mobile-album-meta.wu-mobile-album-actions.wu-pagination.wu-modal.wu-modal-head.wu-modal-body.wu-modal-foot.wu-button-md
Stylesheets · in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css
assets/css/wu-icons.css
assets/css/wu-components.css
assets/css/wu-form-controls.css
application/assets/css/application-shell.css
application/assets/css/application-features.css
Scripts · once, in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js
documentation/assets/js/layout-examples.js
The reference lists use project-root paths. The copyable dependency block and HTML below use paths relative to documentation/starters/, so they work in the delivered starter files. Load each dependency once; keep scripts after content. When moving your starter to public/ or application/, adjust those paths together. Keep its shell controller; a content-only preview does not need to reload it.
Dependencies
Copy Dependencies
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link href="../../assets/css/wu-icons.css" rel="stylesheet" />
<link href="../../assets/css/wu-components.css" rel="stylesheet" />
<link href="../../assets/css/wu-form-controls.css" rel="stylesheet" />
<link href="../../application/assets/css/application-shell.css" rel="stylesheet" />
<link href="../../application/assets/css/application-features.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
<script src="../assets/js/layout-examples.js"></script>
Documentation sample composition using existing source classes. Sample text, record IDs and demo-only hooks are local to this example.
Application · Repeating media cards
Source arrangement: application/moderation.html · .wu-guest-gallery-grid > figure.wu-guest-media; .wu-guest-media__caption; .wu-guest-media__actions
Paste inside the Application starter main.wu-page. Use body class="wu-application wu-page-moderation wu-page-album" with data-page="new-page". These are the styling scopes already used by Moderation, not a new gallery theme.
Keep the starter CSS, then load public/assets/css/guest-album.css and application/assets/css/application-album.css in the listed order. The Application reuses the Guest gallery figure styles; Guest JavaScript is not required here.
This is the source CSS multi-column gallery: three columns, two at ≤991.98px, one below 768px. It is not a row-aligned Bootstrap card grid. Keep each image, filename caption and actions inside the same figure.
View opens a Bootstrap image preview filled from the selected figure. Hide opens a clearly labelled demo dialog. Include both related overlay blocks; Bootstrap owns opening/closing, backdrop and focus.
Load layout-examples.js once after Bootstrap. Do not add guest-album.js or moderation.js just for this layout: their full-page controllers have separate feature roots. Original WebP crops, loading and decoding attributes are kept.
Place the related dialog blocks after .wu-app, before </body>, as in the Application starter. Keep each dialog ID unique when composing examples.
HTML example Ready for the supplied page starter
HTML
Copy HTML
<!-- Paste inside Application starter main.wu-page (inside the existing shell). Asset paths below target documentation/starters/. -->
<section aria-labelledby="docs-grid-title">
<div class="wu-page-head">
<div>
<h2 class="wu-page-title" id="docs-grid-title">Moments from the celebration</h2>
<p class="wu-page-copy">
Six sample photographs. Repeat a figure for each record; use View to inspect a photo.
</p>
</div>
</div>
<p class="wu-help">
Documentation demo: Hide only explains the action. No media is removed or changed.
</p>
<div class="wu-guest-gallery-grid">
<figure class="wu-guest-media">
<img
src="../../public/assets/images/memory-01.webp"
width="960"
height="645"
loading="lazy"
decoding="async"
alt="Friends sharing a wedding selfie"
/>
<figcaption class="wu-guest-media__caption">Celebration_01.jpg</figcaption>
<div class="wu-guest-media__actions">
<button
class="wu-button wu-button-sm wu-button--primary"
type="button"
data-bs-toggle="modal"
data-bs-target="#docs-media-preview"
data-layout-media-open
aria-label="Preview Celebration_01.jpg"
>
View
</button>
<button
type="button"
class="wu-button wu-button-sm wu-button--danger"
data-bs-toggle="modal"
data-bs-target="#docs-grid-action"
data-layout-action="Hide"
data-layout-label="Celebration_01.jpg"
>
Hide
</button>
</div>
</figure>
<figure class="wu-guest-media">
<img
src="../../public/assets/images/memory-02.webp"
width="478"
height="698"
loading="lazy"
decoding="async"
alt="Guests celebrating with the couple"
/>
<figcaption class="wu-guest-media__caption">Celebration_02.jpg</figcaption>
<div class="wu-guest-media__actions">
<button
class="wu-button wu-button-sm wu-button--primary"
type="button"
data-bs-toggle="modal"
data-bs-target="#docs-media-preview"
data-layout-media-open
aria-label="Preview Celebration_02.jpg"
>
View
</button>
<button
type="button"
class="wu-button wu-button-sm wu-button--danger"
data-bs-toggle="modal"
data-bs-target="#docs-grid-action"
data-layout-action="Hide"
data-layout-label="Celebration_02.jpg"
>
Hide
</button>
</div>
</figure>
<figure class="wu-guest-media">
<img
src="../../public/assets/images/memory-01.webp"
width="960"
height="650"
loading="lazy"
decoding="async"
alt="Wedding party gathering together"
/>
<figcaption class="wu-guest-media__caption">Celebration_03.jpg</figcaption>
<div class="wu-guest-media__actions">
<button
class="wu-button wu-button-sm wu-button--primary"
type="button"
data-bs-toggle="modal"
data-bs-target="#docs-media-preview"
data-layout-media-open
aria-label="Preview Celebration_03.jpg"
>
View
</button>
<button
type="button"
class="wu-button wu-button-sm wu-button--danger"
data-bs-toggle="modal"
data-bs-target="#docs-grid-action"
data-layout-action="Hide"
data-layout-label="Celebration_03.jpg"
>
Hide
</button>
</div>
</figure>
<figure class="wu-guest-media">
<img
src="../../public/assets/images/memory-05.webp"
width="756"
height="978"
loading="lazy"
decoding="async"
alt="Bride smiling with friends"
/>
<figcaption class="wu-guest-media__caption">Celebration_04.jpg</figcaption>
<div class="wu-guest-media__actions">
<button
class="wu-button wu-button-sm wu-button--primary"
type="button"
data-bs-toggle="modal"
data-bs-target="#docs-media-preview"
data-layout-media-open
aria-label="Preview Celebration_04.jpg"
>
View
</button>
<button
type="button"
class="wu-button wu-button-sm wu-button--danger"
data-bs-toggle="modal"
data-bs-target="#docs-grid-action"
data-layout-action="Hide"
data-layout-label="Celebration_04.jpg"
>
Hide
</button>
</div>
</figure>
<figure class="wu-guest-media">
<img
src="../../public/assets/images/memory-04.webp"
width="833"
height="952"
loading="lazy"
decoding="async"
alt="Newlyweds together outdoors"
/>
<figcaption class="wu-guest-media__caption">Celebration_05.jpg</figcaption>
<div class="wu-guest-media__actions">
<button
class="wu-button wu-button-sm wu-button--primary"
type="button"
data-bs-toggle="modal"
data-bs-target="#docs-media-preview"
data-layout-media-open
aria-label="Preview Celebration_05.jpg"
>
View
</button>
<button
type="button"
class="wu-button wu-button-sm wu-button--danger"
data-bs-toggle="modal"
data-bs-target="#docs-grid-action"
data-layout-action="Hide"
data-layout-label="Celebration_05.jpg"
>
Hide
</button>
</div>
</figure>
<figure class="wu-guest-media">
<img
src="../../public/assets/images/memory-02.webp"
width="960"
height="650"
loading="lazy"
decoding="async"
alt="Guests smiling during the celebration"
/>
<figcaption class="wu-guest-media__caption">Celebration_06.jpg</figcaption>
<div class="wu-guest-media__actions">
<button
class="wu-button wu-button-sm wu-button--primary"
type="button"
data-bs-toggle="modal"
data-bs-target="#docs-media-preview"
data-layout-media-open
aria-label="Preview Celebration_06.jpg"
>
View
</button>
<button
type="button"
class="wu-button wu-button-sm wu-button--danger"
data-bs-toggle="modal"
data-bs-target="#docs-grid-action"
data-layout-action="Hide"
data-layout-label="Celebration_06.jpg"
>
Hide
</button>
</div>
</figure>
</div>
</section>
<!-- Related Bootstrap dialogs: place after .wu-app, before </body>; include once. -->
<div
class="wu-modal modal fade"
id="docs-media-preview"
tabindex="-1"
aria-labelledby="docs-media-preview-title"
data-layout-media-dialog
>
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div class="modal-content">
<div class="wu-modal-head modal-header">
<h2 class="text-bronze-600 fw-bold" id="docs-media-preview-title" data-layout-media-title>
Sample photo
</h2>
<button class="btn-close" type="button" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="wu-guest-lightbox">
<img
data-layout-media-image
src="../../public/assets/images/memory-01.webp"
alt="Friends sharing a wedding selfie"
/>
</div>
</div>
<div class="wu-modal-foot modal-footer">
<button
class="wu-button wu-button-md wu-button--outline"
type="button"
data-bs-dismiss="modal"
>
Close preview
</button>
</div>
</div>
</div>
</div>
<div
class="wu-modal modal fade"
id="docs-grid-action"
tabindex="-1"
aria-labelledby="docs-grid-action-title"
aria-describedby="docs-grid-action-message"
data-layout-action-dialog
>
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="wu-modal-head modal-header">
<h2 class="text-bronze-600 fw-bold" id="docs-grid-action-title">Demo action</h2>
<button class="btn-close" type="button" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="wu-modal-body modal-body">
<p class="mb-0" id="docs-grid-action-message" data-layout-action-message>
This example does not change records.
</p>
</div>
<div class="wu-modal-foot modal-footer">
<button
class="wu-button wu-button-md wu-button--outline"
type="button"
data-bs-dismiss="modal"
>
Close demo
</button>
</div>
</div>
</div>
</div>
CSS reference & dependencies
.wu-page-head.wu-page-title.wu-page-copy.wu-help.wu-guest-gallery-grid.wu-guest-media.wu-guest-media__caption.wu-guest-media__actions.wu-button.wu-button-sm.wu-button--primary.wu-button--danger.wu-modal.wu-modal-head.wu-guest-lightbox.wu-modal-foot.wu-button-md.wu-button--outline.wu-modal-body
Stylesheets · in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css
assets/css/wu-icons.css
assets/css/wu-components.css
assets/css/wu-form-controls.css
application/assets/css/application-shell.css
application/assets/css/application-features.css
public/assets/css/guest-album.css
application/assets/css/application-album.css
Scripts · once, in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js
documentation/assets/js/layout-examples.js
The reference lists use project-root paths. The copyable dependency block and HTML below use paths relative to documentation/starters/, so they work in the delivered starter files. Load each dependency once; keep scripts after content. When moving your starter to public/ or application/, adjust those paths together. Keep its shell controller; a content-only preview does not need to reload it.
Dependencies
Copy Dependencies
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link href="../../assets/css/wu-icons.css" rel="stylesheet" />
<link href="../../assets/css/wu-components.css" rel="stylesheet" />
<link href="../../assets/css/wu-form-controls.css" rel="stylesheet" />
<link href="../../application/assets/css/application-shell.css" rel="stylesheet" />
<link href="../../application/assets/css/application-features.css" rel="stylesheet" />
<link href="../../public/assets/css/guest-album.css" rel="stylesheet" />
<link href="../../application/assets/css/application-album.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
<script src="../assets/js/layout-examples.js"></script>
Documentation sample composition using existing source classes. Sample text, record IDs and demo-only hooks are local to this example.
Additional existing section references
The following Pricing and Public form references remain unchanged. Their original source-relative paths and context dependencies are retained.
Feature detail section
Source: public/pricing.html · .wu-feature-detail > .wu-feature-detail-grid
This repeatable pricing feature pattern is used for multiple feature blocks on the Pricing page. pricing-enhanced.css is a context dependency.
It is not a global Application card; retain the source media/copy order and responsive CSS.
HTML example
HTML
Copy HTML
<section class="wu-feature-detail" data-feature-section="standard-features" id="standard-features">
<div
class="wu-feature-detail-grid"
data-aos="zoom-in-left"
data-aos-delay="300"
data-aos-duration="500"
>
<div class="wu-feature-detail-copy">
<div class="wu-feature-detail-number">01</div>
<span class="wu-feature-tag wu-feature-tag--included">Included</span>
<h2>Core Collection</h2>
<p>
<strong>Everything needed to start collecting memories is included.</strong>
<br />
Guests contribute without an app or account, uploads can remain in original quality, each
album has a unique URL and QR code, and files transfer into the connected Google Drive.
</p>
<ul class="wu-feature-points">
<li class="wu-feature-point">
<i class="wu-icon wu-icon--cloud-check wu-icon--sm" aria-hidden="true"></i>
<span>No guest app or guest account required</span>
</li>
<li class="wu-feature-point">
<i class="wu-icon wu-icon--cloud-check wu-icon--sm" aria-hidden="true"></i>
<span>Real-time gallery as new guest uploads arrive</span>
</li>
<li class="wu-feature-point">
<i class="wu-icon wu-icon--cloud-check wu-icon--sm" aria-hidden="true"></i>
<span>Unique album link + QR code + printable sharing signs</span>
</li>
<li class="wu-feature-point">
<i class="wu-icon wu-icon--cloud-check wu-icon--sm" aria-hidden="true"></i>
<span>Unlimited guest contributors and multiple albums</span>
</li>
<li class="wu-feature-point">
<i class="wu-icon wu-icon--cloud-check wu-icon--sm" aria-hidden="true"></i>
<span>Guest uploads become available in the connected Google Drive</span>
</li>
</ul>
<a class="wu-text-link" href="guest-template-1.html">See it in the demo guest album →</a>
</div>
<div class="wu-feature-detail-visual wu-v-standard">
<img
class="d-none d-sm-block d-md-none d-lg-block"
src="assets/images/02-pricing-features/feature-01.webp"
alt=""
decoding="async"
loading="lazy"
/>
<img
class="d-block d-sm-none d-md-block d-lg-none"
src="assets/images/02-pricing-features/feature-01-ipad.webp"
alt=""
decoding="async"
loading="lazy"
/>
</div>
</div>
</section>
CSS reference & dependencies
.wu-feature-detail.wu-feature-detail-grid.wu-feature-detail-copy.wu-feature-detail-number.wu-feature-tag.wu-feature-tag--included.wu-feature-points.wu-feature-point.wu-icon.wu-icon--cloud-check.wu-icon--sm.wu-text-link
Stylesheets · in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css
public/assets/css/components.css
public/assets/css/public.css
public/assets/css/pages.css
public/assets/css/signature.css
public/assets/css/pricing-enhanced.css
public/assets/css/site-shell.css
assets/css/wu-icons.css
Scripts · once, in this order
No component JavaScript required.
Dependency paths below are relative to the project root. Source snippet asset paths are relative to public/. Adjust paths when moving a snippet.
Dependencies
Copy Dependencies
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link href="public/assets/css/components.css" rel="stylesheet" />
<link href="public/assets/css/public.css" rel="stylesheet" />
<link href="public/assets/css/pages.css" rel="stylesheet" />
<link href="public/assets/css/signature.css" rel="stylesheet" />
<link href="public/assets/css/pricing-enhanced.css" rel="stylesheet" />
<link href="public/assets/css/site-shell.css" rel="stylesheet" />
<link href="assets/css/wu-icons.css" rel="stylesheet" />
Source excerpt; no component class renaming.
Public form section
Source: public/contact.html · .wu-contact-card .wu-field
Public contact layout uses .wu-field and its Public styling; Application fields use the shared Bootstrap form theme. Do not load both context stacks into the same page.
This preview keeps native browser validation. A documentation guard pauses the final submission; it does not send a support message.
HTML example
HTML
Copy HTML
<form class="wu-contact-card" data-aos="fade-left" data-aos-duration="500">
<div class="wu-contact-two">
<div class="wu-field">
<label for="firstName">First name</label>
<input
autocomplete="given-name"
class="wu-input"
id="firstName"
placeholder="Input your first name"
/>
</div>
<div class="wu-field">
<label for="lastName">Last name</label>
<input
autocomplete="family-name"
class="wu-input"
id="lastName"
placeholder="Input your last name"
/>
</div>
</div>
<div class="wu-field">
<label for="email">Email address</label>
<input
autocomplete="email"
class="wu-input"
id="email"
type="email"
placeholder="Input your Email Address"
/>
</div>
<div class="wu-field">
<label for="topic">What can we help with?</label>
<select class="wu-select" id="topic">
<option>General question</option>
<option>Album / upload help</option>
<option>Google Drive connection</option>
<option>Pricing / purchase</option>
<option>Feedback or idea</option>
</select>
</div>
<div class="wu-field">
<label for="message">Your message</label>
<textarea class="wu-textarea" id="message" placeholder="Write a message"></textarea>
</div>
<button class="wu-button wu-button--primary wu-button-lg" type="button">Send message →</button>
</form>
CSS reference & dependencies
.wu-contact-card.wu-contact-two.wu-field.wu-input.wu-select.wu-textarea.wu-button.wu-button--primary.wu-button-lg
Stylesheets · in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css
public/assets/css/components.css
public/assets/css/public.css
public/assets/css/pages.css
public/assets/css/signature.css
public/assets/css/responsive.css
public/assets/css/site-shell.css
public/assets/css/public-layout.css
assets/css/wu-icons.css
Scripts · once, in this order
No component JavaScript required.
Dependency paths below are relative to the project root. Source snippet asset paths are relative to public/. Adjust paths when moving a snippet.
Dependencies
Copy Dependencies
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link href="public/assets/css/components.css" rel="stylesheet" />
<link href="public/assets/css/public.css" rel="stylesheet" />
<link href="public/assets/css/pages.css" rel="stylesheet" />
<link href="public/assets/css/signature.css" rel="stylesheet" />
<link href="public/assets/css/responsive.css" rel="stylesheet" />
<link href="public/assets/css/site-shell.css" rel="stylesheet" />
<link href="public/assets/css/public-layout.css" rel="stylesheet" />
<link href="assets/css/wu-icons.css" rel="stylesheet" />
Source excerpt; no component class renaming.
Application Shell / Layout
Ownership matters. application-shell.js controls shared navigation/profile. application.js controls page feature flows and guided tour. Bootstrap owns its overlays. Do not duplicate their handlers in a page inline script.
The shell is rendered from source regions. No existing Application CSS or JavaScript has been changed to accommodate documentation.
Application shell & responsive navigation
Source: application/dashboard.html · .wu-app > .wu-sidebar + .wu-main
application-shell.js owns sidebar/scrim, profile menu and language preference. Bootstrap owns native overlays. application.js owns page feature processes and guided tour.
The preview loads the actual shell controller and native overlay blocks, without the full page feature controller. Create Album opens its source modal; submitting is paused here.
Desktop ≥1200px: full sidebar. Tablet 768–1199px: rail with expandable sidebar. Mobile <768px: hidden sidebar and hamburger.
Use the page starter below for the complete script order. Avoid duplicating inline sidebar, profile or overlay lifecycle handlers.
Unavailable in this ZIP: the hidden free-plan QR trigger references #accountUpgradeModal, but that modal is not supplied. The storage.html fallback is also absent; its existing Bootstrap data target opens #googleDriveDrawer. It is not presented as a working upgrade example.
HTML example
HTML
Copy HTML
<div class="wu-app">
<aside aria-label="Main navigation" class="wu-sidebar" id="wuApplicationSidebar">
<div class="wu-sidebar-head">
<a aria-label="WedUploader home" class="wu-brand" href="dashboard.html" data-preserve-plan="">
<img alt="WedUploader" class="wu-brand-full" src="../assets/logo/logo-light.png" />
<img alt="" class="wu-brand-mark" src="../assets/logo/favicon-01.png" />
</a>
<button aria-label="Close navigation" class="wu-sidebar-toggle" type="button">
<i
class="wu-icon wu-icon--sidebar-flip-white wu-icon--m"
style="transform: scaleX(-1);"
></i>
</button>
</div>
<div class="wu-sidebar-scroll">
<button
aria-label="Create Album"
class="wu-create"
data-modal-open="createAlbumModal"
title="Create Album"
type="button"
data-bs-toggle="modal"
data-bs-target="#createAlbumModal"
aria-controls="createAlbumModal"
>
<i class="wu-icon wu-icon--plus wu-icon--sm"></i>
<span class="wu-nav-text">Create Album</span>
</button>
<nav aria-label="Workspace" class="wu-sidebar-nav">
<section aria-labelledby="wuNavGroup0" class="wu-nav-group">
<h2 class="wu-nav-title" id="wuNavGroup0">Features</h2>
<ul class="nav flex-column">
<li class="nav-item">
<a
aria-label="Albums"
class="nav-link wu-nav-link"
href="dashboard.html"
title="Albums"
aria-current="page"
data-preserve-plan=""
>
<span class="wu-nav-icon" data-icon="albums">
<i class="wu-icon wu-icon--apps-2 wu-icon--sm"></i>
</span>
<span class="wu-nav-text">Albums</span>
</a>
</li>
<li class="nav-item">
<a
aria-label="Custom Background"
class="nav-link wu-nav-link"
href="custom-background.html"
data-tour-target="background"
title="Custom Background"
>
<span class="wu-nav-icon">
<i class="wu-icon wu-icon--gallery-2 wu-icon--sm"></i>
</span>
<span class="wu-nav-text">Custom Background</span>
</a>
</li>
<li class="nav-item">
<a
aria-label="Premium QR Templates"
class="nav-link wu-nav-link"
href="qr-templates.html"
title="Premium QR Templates"
data-tour-target="qr-signs"
data-plan-view="premium"
>
<span class="wu-nav-icon">
<i class="wu-icon wu-icon--crown-2 wu-icon--sm"></i>
</span>
<span class="wu-nav-text">Premium QR Templates</span>
</a>
<button
class="nav-link wu-nav-link is-entitlement-link"
type="button"
data-unlock-feature="qrTemplates"
data-bs-toggle="modal"
data-bs-target="#accountUpgradeModal"
data-plan-view="free"
hidden=""
>
<span class="wu-nav-icon">
<i class="wu-icon wu-icon--crown-2 wu-icon--sm" aria-hidden="true"></i>
</span>
<span class="wu-nav-text">Premium QR Templates</span>
</button>
</li>
</ul>
</section>
<section aria-labelledby="wuNavGroup1" class="wu-nav-group">
<h2 class="wu-nav-title" id="wuNavGroup1">Connected Services</h2>
<ul class="nav flex-column">
<li class="nav-item">
<a
aria-label="WedSigns.ai"
class="nav-link wu-nav-link"
title="WedSigns.ai"
data-bs-toggle="offcanvas"
data-bs-target="#wedsignsDrawer"
aria-controls="wedsignsDrawer"
>
<span class="wu-nav-icon">
<i class="wu-icon wu-icon--magic wu-icon--sm"></i>
</span>
<span class="wu-nav-text">WedSigns.ai</span>
<span class="wu-nav-pill info">Free</span>
</a>
</li>
</ul>
</section>
<section aria-labelledby="wuNavGroup2" class="wu-nav-group">
<h2 class="wu-nav-title" id="wuNavGroup2">Helpful Link & Tips</h2>
<ul class="nav flex-column">
<li class="nav-item">
<a
aria-label="Guided Tour"
class="nav-link wu-nav-link"
data-tour-trigger="dashboard"
href="dashboard.html?tour=dashboard"
title="Guided Tour"
data-preserve-plan=""
>
<span class="wu-nav-icon">
<i class="wu-icon wu-icon--guide wu-icon--sm"></i>
</span>
<span class="wu-nav-text">Guided Tour</span>
</a>
</li>
<li class="nav-item">
<a
aria-label="Tutorials"
class="nav-link wu-nav-link"
href="tutorials.html"
title="Tutorials"
>
<span class="wu-nav-icon">
<i class="wu-icon wu-icon--info-2 wu-icon--sm"></i>
</span>
<span class="wu-nav-text">Tutorials</span>
</a>
</li>
<li class="nav-item">
<a aria-label="FAQs" class="nav-link wu-nav-link" href="faq.html" title="FAQs">
<span class="wu-nav-icon" data-icon="faq">
<i class="wu-icon wu-icon--faq wu-icon--sm"></i>
</span>
<span class="wu-nav-text">FAQs</span>
</a>
</li>
<li class="nav-item">
<a
aria-label="Contact Us"
class="nav-link wu-nav-link"
href="contact.html"
title="Contact Us"
aria-current="page"
>
<span class="wu-nav-icon">
<i class="wu-icon wu-icon--contact wu-icon--sm"></i>
</span>
<span class="wu-nav-text">Contact Us</span>
</a>
</li>
</ul>
</section>
</nav>
<div class="wu-sidebar-account">
<div class="wu-sidebar-account-top">
<span>Google Drive</span>
<span class="wu-nav-pill success">Connected</span>
</div>
<div class="wu-sidebar-storage">7.83 GB of 400 GB used</div>
<div class="wu-mini-progress">
<span></span>
</div>
<a
class="wu-storage-link"
href="storage.html"
data-bs-toggle="offcanvas"
data-bs-target="#googleDriveDrawer"
aria-controls="googleDriveDrawer"
>
<span>Check Storage Quota</span>
<span class="wu-nav-icon">
<i class="wu-icon wu-icon--arrow-right-gold wu-icon--sm"></i>
</span>
</a>
</div>
</div>
</aside>
<div class="wu-main">
<header class="wu-topbar navbar">
<div class="wu-top-left">
<button
aria-controls="wuApplicationSidebar"
aria-expanded="false"
aria-label="Open navigation"
class="wu-mobile-menu"
data-sidebar-open=""
type="button"
>
<span aria-hidden="true" class="wu-hamburger">
<i class="wu-icon wu-icon--sidebar-flip wu-icon--m"></i>
</span>
</button>
<div aria-label="Breadcrumb" class="wu-breadcrumb">
<span class="wu-breadcrumb-home">
<i class="wu-icon wu-icon--home wu-icon--xs"></i>
</span>
<span>Home</span>
<span>›</span>
<strong>Dashboard</strong>
</div>
</div>
<div class="wu-top-right">
<span class="wu-clock" data-clock=""></span>
<button
aria-controls="wuProfileMenu"
aria-expanded="false"
aria-label="Account menu"
class="wu-profile-trigger"
data-profile-trigger=""
type="button"
>
<span class="wu-avatar">DM</span>
<span class="wu-profile-name">Derick</span>
<span>
<i class="wu-icon wu-icon--chevron-down wu-icon--xs"></i>
</span>
</button>
<div class="wu-profile-menu" id="wuProfileMenu">
<div class="wu-profile-welcome">
Welcome back,
<strong class="text-gold-500">Derick Metzger</strong>
</div>
<a
class="wu-profile-item"
data-bs-toggle="offcanvas"
data-bs-target="#settingsDrawer"
aria-controls="settingsDrawer"
>
<i class="wu-icon wu-icon--setting wu-icon--sm"></i>
Settings
</a>
<a
class="wu-profile-item is-danger"
data-bs-toggle="modal"
data-bs-target="#wuLogoutDialog"
aria-controls="wuLogoutDialog"
>
<i class="wu-icon wu-icon--logout wu-icon--sm"></i>
Log out
</a>
</div>
</div>
</header>
<main class="wu-page" id="mainContent">
<section class="wu-page-head">
<div>
<h1 class="wu-page-title">Hi, Derick Metzger.</h1>
<p class="wu-page-copy">
Manage every WedUploader album from one scalable workspace. Frequent actions stay
visible; deeper configuration lives inside each album.
</p>
</div>
</section>
</main>
<footer class="wu-footer">
<span class="wu-footer-copyright">©2026 WedUploader - All Rights Reserved</span>
<div class="wu-footer-actions">
<nav aria-label="Legal" class="wu-footer-links">
<a href="https://weduploader.com/privacy">Privacy Policy</a>
<a href="https://weduploader.com/terms">Terms of Use</a>
<a href="https://weduploader.com/contact-us">Contact</a>
</nav>
<details class="wu-footer-legal">
<summary>
Legal Docs
<i class="wu-icon wu-icon--chevron-down wu-icon--xs"></i>
</summary>
<nav aria-label="Legal documents">
<a href="https://weduploader.com/privacy">Privacy Policy</a>
<a href="https://weduploader.com/terms">Terms of Use</a>
<a href="https://weduploader.com/contact-us">Contact</a>
</nav>
</details>
<div class="dropdown wu-locale">
<button
aria-expanded="false"
aria-label="Language: English"
class="wu-locale-trigger"
data-bs-auto-close="true"
data-bs-toggle="dropdown"
id="wuLocaleToggle"
type="button"
>
<span aria-hidden="true" class="wu-locale-flag" data-wu-locale-current-flag="">🇺🇸</span>
<span data-wu-locale-current-code="">English(US)</span>
<i class="wu-icon wu-icon--chevron-down wu-icon--xs"></i>
</button>
<ul
aria-labelledby="wuLocaleToggle"
class="dropdown-menu dropdown-menu-end wu-locale-menu"
>
<li>
<button
class="dropdown-item wu-locale-option"
data-flag="🇺🇸"
data-label="English"
data-wu-locale-option="en"
type="button"
>
<span aria-hidden="true">🇺🇸</span>
<span>English</span>
<span aria-hidden="true" class="wu-locale-check">✓</span>
</button>
</li>
<li>
<button
class="dropdown-item wu-locale-option"
data-flag="🇩🇪"
data-label="Deutsch"
data-wu-locale-option="de"
type="button"
>
<span aria-hidden="true">🇩🇪</span>
<span>Deutsch</span>
<span aria-hidden="true" class="wu-locale-check">✓</span>
</button>
</li>
<li>
<button
class="dropdown-item wu-locale-option"
data-flag="🇫🇷"
data-label="Français"
data-wu-locale-option="fr"
type="button"
>
<span aria-hidden="true">🇫🇷</span>
<span>Français</span>
<span aria-hidden="true" class="wu-locale-check">✓</span>
</button>
</li>
<li>
<button
class="dropdown-item wu-locale-option"
data-flag="🇵🇹"
data-label="Português"
data-wu-locale-option="pt"
type="button"
>
<span aria-hidden="true">🇵🇹</span>
<span>Português</span>
<span aria-hidden="true" class="wu-locale-check">✓</span>
</button>
</li>
<li>
<button
class="dropdown-item wu-locale-option"
data-flag="🇪🇸"
data-label="Español"
data-wu-locale-option="es"
type="button"
>
<span aria-hidden="true">🇪🇸</span>
<span>Español</span>
<span aria-hidden="true" class="wu-locale-check">✓</span>
</button>
</li>
<li>
<button
class="dropdown-item wu-locale-option"
data-flag="🇮🇹"
data-label="Italiano"
data-wu-locale-option="it"
type="button"
>
<span aria-hidden="true">🇮🇹</span>
<span>Italiano</span>
<span aria-hidden="true" class="wu-locale-check">✓</span>
</button>
</li>
<li>
<button
class="dropdown-item wu-locale-option"
data-flag="🇮🇳"
data-label="हिन्दी"
data-wu-locale-option="hi"
type="button"
>
<span aria-hidden="true">🇮🇳</span>
<span>हिन्दी</span>
<span aria-hidden="true" class="wu-locale-check">✓</span>
</button>
</li>
</ul>
<select aria-label="Choose interface language" data-wu-language="" hidden="">
<option value="en">English</option>
<option value="de">Deutsch</option>
<option value="fr">Français</option>
<option value="pt">Português</option>
<option value="es">Español</option>
<option value="it">Italiano</option>
<option value="hi">हिन्दी</option>
</select>
</div>
</div>
</footer>
</div>
</div>
<!-- Related source overlay blocks required by these triggers. -->
<div
class="offcanvas offcanvas-end wu-drawer wu-settings-drawer"
tabindex="-1"
id="settingsDrawer"
aria-labelledby="settingsDrawerTitle"
>
<div class="offcanvas-header">
<h2 class="offcanvas-title" id="settingsDrawerTitle">Settings</h2>
<button
type="button"
class="btn-close"
data-bs-dismiss="offcanvas"
aria-label="Close Settings"
></button>
</div>
<div class="offcanvas-body">
<div class="wu-drawer-profile">
<div class="wu-drawer-avatar" aria-hidden="true">DM</div>
<h3>Derick Metzger</h3>
</div>
<div class="wu-settings-sections">
<div class="wu-setting-block wu-setting-notification">
<label for="settingsEmailNotification">Email notification</label>
<div class="form-check form-switch">
<input
class="form-check-input"
type="checkbox"
role="switch"
id="settingsEmailNotification"
aria-describedby="settingsNotificationState"
/>
<span class="form-check-label" id="settingsNotificationState">Off</span>
</div>
</div>
<div class="wu-setting-block">
<h3 class="wu-setting-title justify-content-start">Event Manager</h3>
<p class="wu-help mb-0" id="eventManagerHelp">
Event managers can help manage WedUploader albums and account actions. Google Drive access
is not automatically granted. You may have up to
<strong>2 email addresses</strong>
, per account, active at any given time.
</p>
<label class="visually-hidden" for="eventManagerEmail">Event manager email address</label>
<input
class="wu-input"
id="eventManagerEmail"
type="email"
placeholder="Email Address"
aria-describedby="eventManagerHelp"
/>
<div class="wu-settings-add">
<button class="wu-button wu-button--ghost" type="button" data-toast="Event manager added">
<i class="wu-icon wu-icon--plus wu-icon--sm" aria-hidden="true"></i>
Add Email Address (1 Left)
</button>
</div>
</div>
<div class="wu-setting-block">
<h3 class="wu-setting-title justify-content-start">Transfer Account</h3>
<p class="wu-help mb-0">
The existing transfer flow moves the WedUploader account to a new email address. The
receiving account must accept the transfer and Google Drive permission.
</p>
<button
class="wu-button wu-button--danger wu-settings-transfer"
type="button"
data-toast="Transfer flow opened"
>
Transfer your Account
<i class="wu-icon wu-icon--cloud-share wu-icon--sm" aria-hidden="true"></i>
</button>
</div>
</div>
</div>
</div>
<div
class="offcanvas offcanvas-end wu-drawer wu-drive-drawer"
tabindex="-1"
id="googleDriveDrawer"
aria-labelledby="googleDriveDrawerTitle"
>
<div class="offcanvas-header">
<h2 class="offcanvas-title" id="googleDriveDrawerTitle">Google Drive & Storage</h2>
<button
type="button"
class="btn-close"
data-bs-dismiss="offcanvas"
aria-label="Close Google Drive and storage"
></button>
</div>
<div class="offcanvas-body">
<div class="wu-drive-status">
<span>Connection Status</span>
<span class="wu-drive-connected">Connected</span>
</div>
<p class="wu-drive-copy">
We recommend having at least 5 GB of space remaining in your Google account. If you are not
comfortable with the remaining storage space in your account, you can easily purchase more
through
<a href="https://one.google.com/" target="_blank" rel="noopener noreferrer">Google here.</a>
</p>
<article class="wu-drive-storage-card">
<small>Total storage</small>
<strong>400 GB</strong>
<p>7.83 GB of 400 GB used</p>
<div
class="progress wu-drive-meter"
role="progressbar"
aria-label="Google Drive storage used"
aria-valuenow="7.83"
aria-valuemin="0"
aria-valuemax="400"
aria-valuetext="7.83 GB of 400 GB used"
>
<div class="progress-bar" style="width: 1.9575%"></div>
</div>
<span>Current account storage shown from the connected Drive state.</span>
<img
class="wu-drive-logo"
src="../assets/images/gdrive.png"
alt="Google Drive"
width="76"
height="68"
/>
</article>
<div class="wu-drive-note">
Guests upload through WedUploader, while the files are sent to the connected Google Drive
account.
</div>
<button
type="button"
class="wu-button wu-button--outline--light wu-drive-check"
data-toast="Google Drive connection checked"
>
<i class="wu-icon wu-icon--link wu-icon--sm" aria-hidden="true"></i>
Check Connection
</button>
</div>
</div>
<div
class="offcanvas offcanvas-end wu-drawer wu-wedsigns-drawer"
tabindex="-1"
id="wedsignsDrawer"
aria-labelledby="wedsignsDrawerTitle"
>
<div class="offcanvas-header">
<h2 class="offcanvas-title" id="wedsignsDrawerTitle">WedSigns.ai Configuration</h2>
<button
type="button"
class="btn-close"
data-bs-dismiss="offcanvas"
aria-label="Close Wedsigns Configuration"
></button>
</div>
<div class="offcanvas-body">
<div class="wu-drive-status mb-4">
<span>Connection Status</span>
<span class="wu-drive-connected">Connected</span>
</div>
<section class="wu-card">
<div class="wu-card-body">
<p class="text-neutral-500 mb-3">
Create wedding QR signs with AI in WedSigns.ai. It opens as a separate service and is free
for WedUploader users.
</p>
<div
class="d-flex flex-column flex-sm-row gap-3 align-items-center justify-content-between"
>
<button
class="wu-button wu-button--primary wu-button-md"
data-toast="WedSigns.ai opened"
type="button"
>
Open WedSigns.ai
<i class="wu-icon wu-icon--arrow-top-right wu-icon--sm" aria-hidden="true"></i>
</button>
<a type="button" href="" class="text-danger-500">Disconnect</a>
</div>
</div>
</section>
</div>
</div>
<div
class="modal fade wu-modal wu-logout-modal"
id="wuLogoutDialog"
tabindex="-1"
aria-labelledby="wuLogoutTitle"
aria-describedby="wuLogoutDescription"
aria-hidden="true"
>
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-body p-4">
<div class="wu-logout-icon m-auto mb-4">
<i class="wu-icon wu-icon--logout wu-icon--xl"></i>
</div>
<h5 id="wuLogoutTitle" class="mb-1 text-center">Log out of WedUploader?</h5>
<p id="wuLogoutDescription" class="text-center text-neutral-500">
You cannot undo deletions. Are you sure you want to delete this WedUploader album?
</p>
<div class="wu-logout-actions mt-4">
<button type="button" class="wu-button" data-bs-dismiss="modal">Cancel</button>
<a class="wu-button wu-button--danger" data-logout-confirm href="../public/login.html">
Log out
</a>
</div>
</div>
</div>
</div>
</div>
<div
class="wu-modal modal fade"
id="createAlbumModal"
tabindex="-1"
aria-labelledby="createAlbumModalTitle"
aria-hidden="true"
>
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div class="wu-modal-card modal-content">
<form id="createAlbumForm">
<div class="wu-modal-head modal-header">
<h2 class="text-bronze-600 fw-bold" id="createAlbumModalTitle">Create Album</h2>
<button
class="btn-close"
data-modal-close=""
type="button"
data-bs-dismiss="modal"
aria-label="Close"
></button>
</div>
<div class="wu-modal-body modal-body">
<div class="mb-3">
<label for="eventTitle" class="form-label wu-label">
<span class="text-danger-500">*</span>
Event title
</label>
<input
id="eventTitle"
class="form-control wu-input"
name="title"
placeholder="Emma & Liam Wedding"
required
/>
</div>
<div class="mb-3">
<label for="folderName" class="form-label wu-label">
<span class="text-danger-500">*</span>
Drive folder name
</label>
<input
id="folderName"
class="form-control wu-input"
name="folder"
placeholder="Example: emma-liam"
required
/>
</div>
<div class="mb-3">
<label for="eventDate" class="form-label wu-label">
<span class="text-danger-500">*</span>
Event Date
</label>
<input
id="eventDate"
class="form-control wu-input"
name="date"
placeholder="DD / MM / YY"
required
type="date"
/>
</div>
<div class="mb-3">
<label class="form-label wu-label">Gallery visibility</label>
<div class="form-check form-switch wu-form-switch">
<input
class="form-check-input"
type="checkbox"
role="switch"
id="largeSwitch"
name="public"
checked
aria-describedby="largeSwitchHelp"
/>
<label class="form-check-label" for="largeSwitch">Public</label>
<small class="wu-form-switch-help" id="largeSwitchHelp">
Uploaded photos will be visible to guests.
</small>
</div>
</div>
</div>
<div class="wu-modal-foot justify-content-between modal-footer">
<button
class="wu-button wu-button-md wu-button--outline"
data-modal-close=""
type="button"
data-bs-dismiss="modal"
>
Cancel
</button>
<button
class="wu-button wu-button-md wu-button--primary"
data-modal-open="loadingModal"
data-bs-toggle="modal"
data-bs-target="#loadingModal"
aria-controls="loadingModalTitle"
>
Create Album
</button>
</div>
</form>
</div>
</div>
</div>
<div
class="wu-modal modal fade"
id="loadingModal"
tabindex="-1"
aria-labelledby="loadingModalTitle"
aria-describedby="loadingModalDescription"
aria-hidden="true"
data-bs-backdrop="static"
data-bs-keyboard="false"
>
<div class="modal-dialog modal-dialog-centered">
<div class="wu-modal-card modal-content">
<div class="wu-modal-body modal-body text-center" role="status" aria-live="polite">
<div data-album-submit-animation aria-hidden="true">
<div class="preloader-img">
<img src="../assets/logo/apple-touch-icon-01.png" alt="" />
</div>
</div>
<h6 id="createAlbumLoadingTitle" class="mb-1 fw-bold">Processing</h6>
<p id="createAlbumLoadingDescription" class="mb-0 text-neutral-500">Please Wait</p>
</div>
</div>
</div>
</div>
CSS reference & dependencies
.wu-app.wu-sidebar.wu-sidebar-head.wu-brand.wu-brand-full.wu-brand-mark.wu-sidebar-toggle.wu-icon.wu-icon--sidebar-flip-white.wu-sidebar-scroll.wu-create
Stylesheets · in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css
assets/css/wu-icons.css
assets/css/wu-components.css
assets/css/wu-form-controls.css
application/assets/css/application-shell.css
application/assets/css/application-features.css
Scripts · once, in this order
https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js
application/assets/js/application-shell.js
Dependency paths below are relative to the project root. Source snippet asset paths are relative to application/. Adjust paths when moving a snippet.
Dependencies
Copy Dependencies
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link href="assets/css/wu-icons.css" rel="stylesheet" />
<link href="assets/css/wu-components.css" rel="stylesheet" />
<link href="assets/css/wu-form-controls.css" rel="stylesheet" />
<link href="application/assets/css/application-shell.css" rel="stylesheet" />
<link href="application/assets/css/application-features.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
<script src="application/assets/js/application-shell.js"></script>
Original shell regions composed around the original page heading. Dashboard feature table intentionally excluded; related shell overlays supplied as preview support.
Shared identity and icons live under assets/; page media and ornaments stay in their existing context. Paths below are generated from the supplied ZIP.
Two icon mechanisms exist. Source pages use both <i class="wu-icon wu-icon--…"> from wu-icons.css and <img src="../assets/icons/…svg">. Reuse an existing icon; verify the modifier exists before adding it.
assets/logo/
assets/logo/logo-light.png
assets/logo/favicon-02.png
assets/logo/apple-touch-icon-01.png
assets/logo/apple-touch-icon-02.png
assets/logo/favicon-01.png
assets/logo/logo-dark-cream.png
assets/logo/apple-touch-icon-03.png
assets/icons/
assets/icons/check.svg
assets/icons/microphone.svg
assets/icons/palette.svg
assets/icons/info.svg
assets/icons/cross.svg
assets/icons/flag-dark.svg
assets/icons/arrow-right-dark.svg
public/assets/images/
public/assets/images/memory-09.webp
public/assets/images/memory-02.webp
public/assets/images/memory-10.webp
public/assets/images/memory-08.webp
public/assets/images/memory-11.webp
public/assets/images/resources-01.jpg
public/assets/images/memory-15.webp
public/assets/ornaments/
public/assets/ornaments/ornament-4.webp
public/assets/ornaments/ornament-6.webp
public/assets/ornaments/ornament-2.webp
public/assets/ornaments/ornament-8.webp
public/assets/ornaments/ornament-5.webp
public/assets/ornaments/ornament-1.webp
public/assets/ornaments/ornament-3.webp
application/assets/images/
application/assets/images/qr.svg
application/assets/images/memory-sheet.jpg
application/assets/images/editorial-collage.png
application/assets/images/amelia-noah.jpg
application/assets/images/sophia-ethan.jpg
application/assets/images/guestfacing-thumbnails.png
Image & ornament usage
Preserve intrinsic width/height, object-fit/crop classes, alt text, lazy loading and decoding attributes from the source component. Gallery photos use local WebP files. Logos/icons use SVG or PNG as supplied. Public ornaments are raster WebP assets; do not redraw them as ad-hoc CSS.
HTML
Copy HTML
<img
src="assets/images/memory-01.webp"
width="960"
height="645"
loading="lazy"
decoding="async"
alt="Friends sharing a wedding selfie"
/>
From a Public HTML file: assets/images/memory-01.webp. From an Application HTML file: ../public/assets/images/memory-01.webp. CSS URLs resolve relative to the stylesheet, not the HTML file. Avoid guessing kebab-case names: inspect assets/icons/, wu-icons.css and the source callsite.
Start from the matching context, preserve load order, then add only the feature markup/scripts the new page needs. The starter files are documentation examples, not new production pages. Their links/assets are resolved for documentation/starters/; adjust them to the original Public or Application folder when moving a starter. Empty Public header destinations are resolved from matching source footer links. The Application demo redirect is resolved to the supplied dashboard.
Starter first, pattern second.
These starter files provide the shell and dependencies.
Use
Reusable Layout Patterns for populated content to paste into that shell. New sample snippets already use the starter folder’s asset paths; follow each pattern’s body-class and CSS notes before wiring a feature handler.
Create a Public page
Copy the relevant Public head/body shell. Use the source page whose structure matches your change.
Keep the current header, mobile panel and backdrop together. Load navigation.js once.
Add existing components inside .wu-container and .wu-section. Keep page-specific overrides in public/assets/css/your-page.css, loaded after the shared/context styles.
If retaining data-aos attributes, include AOS CSS/JS and initialize it as in the source page. Documentation preview pauses animation only; source code is not changed.
Create an Application page
Keep .wu-app, .wu-sidebar, .wu-main, .wu-topbar and .wu-page anatomy. Use a unique body data-page value.
Keep Bootstrap → wu-core.js → application-shell.js → application.js order. Add only the necessary page controllers after those.
Keep IDs used by triggers and source controllers. Rename an instance consistently across aria attributes and data-bs-target if adding another instance.
Do not copy a second inline sidebar/profile/focus handler. Modal/offcanvas show/hide belongs to Bootstrap.
Small extensions
CSS
Copy CSS
/* Add to your context-specific page stylesheet, not the shared library. */
.your-page-note {
color: var(--wu-neutral-700);
padding: var(--wu-space-8);
border-radius: var(--wu-radius-sm);
}
This is an extension recipe, not a new WedUploader component class. For JavaScript, choose one owner for each event. Use feature root guards and existing data hooks; avoid global form prevention, duplicate click handlers or manually toggling Bootstrap .show/backdrop styles.
Run locally & hand off
Open the project through a local static server when testing all original pages. For example, run python3 -m http.server 8000 from the project root, then open /documentation/. The documentation catalog itself uses classic scripts instead of fetch, so direct file opening is also supported subject to browser/CDN restrictions.
See SOURCE_MAP.json for source selectors, dependencies, token values, asset inventory and hashes. Backend behavior, microphone permission, and real media delivery require their own integration testing.