Building Blocks

Modal & overlay patterns

Accessible modal dialogs, GDPR cookie consent banners, and exit-intent popups — keyboard-navigable, focus-trapped, and deployed to your server through a single conversation with Claude.

Accessible Modal Dialog

A fully accessible modal dialog with focus trap, Escape-key close, click-outside dismiss, and animated entry — built on the native <dialog> element with a vanilla JS div-based fallback for older browsers. No library required.

HTML CSS Vanilla JS ARIA
  • Native <dialog> element with showModal() / close() API; JS div-based fallback for older Safari
  • CSS ::backdrop pseudo-element with background: rgba(0,0,0,0.75) and backdrop-filter: blur(4px)
  • Entry animation: opacity 0→1 + scale(0.96→1) 200ms ease-out; exit reverses on close
  • Focus trap: Tab and Shift+Tab cycle within focusable modal elements only; first focusable element receives focus on open
  • Escape key closes; click on backdrop closes; close × button closes — all three restore focus to the triggering element
  • role="dialog", aria-modal="true", aria-labelledby wired to modal heading — WCAG 2.1 AA compliant
  • data-modal-trigger="modal-id" attribute on any button opens any modal by ID — no per-button JS wiring needed
Prompt to use with Claude

Add an accessible modal dialog to my site. Use the native <dialog> element with a JS div fallback. Include a focus trap (Tab cycles within modal only), Escape-key close, click-on-backdrop close, and an animated entry (opacity + scale 0.96→1). Apply role="dialog", aria-modal="true", and aria-labelledby pointing to the modal heading. Any button with data-modal-trigger="modal-id" should open the matching modal. Restore focus to the trigger on close. Match my site's colour scheme.

GDPR Cookie Consent Banner

A bottom-bar cookie consent banner with Accept All, Reject, and Manage Cookies options. Stores preference in localStorage, conditionally injects Google Analytics, and includes a second-layer preferences panel. GDPR and UK PECR compliant.

HTML CSS Vanilla JS localStorage GDPR
  • Fixed bottom bar with z-index: 9990, brand-colour Accept All button, ghost Reject button, and “Manage Cookies” text link
  • Slide-up entry animation (translateY(100%→0)) on first visit; hidden immediately if preference is already stored in localStorage
  • localStorage.setItem('cookie-consent', 'accepted'|'rejected') — banner never shows again after a choice is made
  • Google Analytics (or Google Tag Manager) script injected into <head> dynamically only after ‘accepted’ — never loaded on initial page render
  • Optional second-layer “Manage Cookies” modal panel listing cookie categories (Necessary, Analytics, Marketing) with individual toggle switches
  • PHP helper cookie_consent_check() reads $_COOKIE['cookie_consent'] for server-side conditional rendering when needed
Prompt to use with Claude

Add a GDPR cookie consent banner to my site. Show a fixed bottom bar on first visit with Accept All, Reject, and Manage Cookies buttons. Store the preference in localStorage and never show again after a choice. Only inject Google Analytics (GA ID: G-XXXXXXXX) after the user accepts. Add a second-layer Manage Cookies panel with toggle switches for Analytics and Marketing categories. Match my site's style.

Exit-Intent Popup

A conversion-focused popup that fires when the user moves their cursor toward the browser chrome, with a sessionStorage gate so it shows at most once per session. Includes a time-on-page trigger fallback for mobile devices.

HTML CSS Vanilla JS sessionStorage
  • Desktop trigger: document.addEventListener('mouseleave') fires when event.clientY < 20 (cursor exits viewport toward the tab bar)
  • Mobile fallback: fires after a configurable time-on-page (default 45 seconds) — device detected via navigator.maxTouchPoints > 0
  • sessionStorage.setItem('exit-popup-shown', '1') gates the popup to one appearance per browser session
  • Centred overlay modal: semi-transparent dark background, card with headline, body paragraph, primary CTA button, and plain-text “No thanks” dismiss link
  • Entry animation: opacity 0→1 + translateY(16px→0) 260ms ease-out
  • Escape key and click-outside close; body scroll lock applied on open and released on close
  • All copy and trigger timings configurable via data-* attributes on the popup element — no JS edits required for content changes
Prompt to use with Claude

Add an exit-intent popup to my site. On desktop, fire when the mouse moves toward the browser chrome (clientY < 20). On mobile, fire after 45 seconds on the page. Show it at most once per session using sessionStorage. The popup should have a headline "Before you go…", a short body paragraph, a primary CTA button linking to /pricing, and a plain "No thanks" dismiss link. Close on Escape and click-outside. Match my site's design.

Overlays that don’t break the experience

Every overlay pattern is accessible, keyboard-navigable, and tested against WCAG 2.1 AA. No jQuery, no plugin overhead, no accessibility debt shipped to production.

Keyboard accessible

Focus traps, Escape-key close, and aria-modal attributes are included in every pattern. Screen reader and keyboard-only users get a consistent, navigable experience.

No framework needed

Vanilla JS only — no jQuery, no Bootstrap, no Alpine. Each pattern is self-contained and adds under 2KB of JS to your page weight.

GDPR-ready

The cookie consent pattern only fires analytics after explicit consent — compliant with GDPR and UK PECR without paying for a third-party consent management platform.

Iterable in seconds

Change the popup headline, adjust the trigger delay, or add a form field. Describe the change to Claude and it’s updated on your live site within seconds.

← All building blocks Navigation & Menu patterns JS Animation patterns Contact Form patterns

Deploy overlays with Claude CMS

From £6.99/month. First month free — no credit card required. Add an accessible modal, GDPR cookie banner, or exit-intent popup to your site in one conversation.