section-029

Folded Letter Signup

Vault only: not sold separatelyGet the Vault

A newsletter signup for a small hotel where a journal-style landing opens on past letters that fold in thirds, slide away and open again as visitors choose one to read.

advanced
8 more details
3d-transformspaper-foldinterruptible-transitionsaccessible-tabsform-validationprogressive-enhancementcontainer-queriesresponsive-section

This section reads better at your own screen size than in the frame below:

Released

About this section

Folded Letter Signup Section helps visitors decide a newsletter is worth their inbox before they sign up. It opens like a journal's landing page, with a masthead and cadence notes. Past letters lie in a pool of lamplight, one at a time, as real paper: a letterhead with a photograph, the opening of the letter, and what else was in it. An index of past letters sits beside them. Choosing one folds the open letter in thirds, slides it away, brings the next one in folded with the letterhead on the outside, and opens it again, top third first.

Read the full section overview

Below the letters, the signup says exactly what arrives and how often, then asks for an email address. The form is ordinary semantic HTML with inline validation and a documented endpoint for the buyer's mailing list; in its demo state it says plainly that nothing was sent.

The fictional Ferrow House example is a nine-room hotel on the north Norfolk coast that publishes quarterly dispatches. Every letter is ordinary markup, so the same design suits a restaurant, a members' club, a winery or a studio newsletter.

Folded Letter Signup - website section preview

What's included

10 items
  • Past letters as paper in a pool of lamplight, each folding in thirds with a lit crease shade and a shadow that follows the fold
  • The folded letter shows its own letterhead on the outside, generated from the letter's markup
  • Interruptible transitions: choosing the previous letter mid-move reverses it, rapid choices hurry the move and settle on the last one
  • Accessible tabs with arrow, Home and End keys, working by touch and pointer
  • Signup form with visible labels, inline validation messages, a honeypot field and a status region
  • Demo mode that states nothing was sent; live mode posts to the buyer's endpoint by fetch or native form submission
  • Opening facts on what arrives, how often and what never arrives
  • Four generated photographs, each an ordinary replaceable image, on a CSS-only ground
  • Readable fallback without JavaScript: every letter open, one after another, with the index as in-page links
  • Independent instances, unique IDs and exact teardown

Perfect for

4 use cases
  • Boutique hotels, inns and guesthouses with a seasonal newsletter
  • Restaurants, wineries and members' clubs sending a letter from the house
  • Studios, makers and writers who want past issues to sell the next one
  • Any newsletter where showing a real past issue is the best argument for subscribing

How it works

3 sections

Each letter is an article with three panels in markup, and the panels share the letter's height equally through CSS grid, so no measurement is needed. With JavaScript the letters stack on one spot and the index becomes a tablist. The script adds a back face to the top and bottom panels and copies the letterhead onto the outside of the fold.

A change of letter is one GSAP timeline: the bottom third turns up and the top third turns down over it with a shade that deepens as each panel stands on edge, the shadow beneath shrinks to the folded third, the letter slides off, and the next one arrives folded and opens. Choosing the letter it came from reverses the timeline; choosing a third letter hurries the move and then goes on. Fades apply to the paper surfaces rather than the letter, because opacity on the letter would flatten its 3D panels.

With reduced motion the letters switch instantly, and changing the preference mid-move settles on the chosen letter. The form validates on submit and then as the visitor types, and it never sends in demo mode.

Difficulty Advanced
Includes HTML + JS + CSS source, documentation, AI setup prompt, lifetime updates

Lighthouse, as measured

Google Lighthouse on this website section's demo, from the latest scan. A measurement of the demo as shipped, not a promise for your page.

Accessibility
100
Best practices
100

No performance score, on purpose. That figure depends on how you deploy: your server's compression and caching, your CDN, the connection and the device doing the test, none of which the code controls. The same page can score very differently on two consecutive runs, so measure it where it will live.

Vault only

Get the Vault to use this section.

The Vault includes Folded Letter Signup, the HTML, CSS and JavaScript source, the full documentation, an AI setup prompt for your editor, and every update we ship to it. Standard license: unlimited personal and commercial projects. Every paid product is tested for desktop and mobile layouts, reduced-motion handling, animation cleanup and keyboard controls wherever there is something to operate. Sections are available only in the Vault for now while the collection is small.

Documentation

Quick Start

Copy these into your project:

  • the <section class="flx"> element from index.html, between the EXTRACT START and EXTRACT END comments
  • assets/style.css
  • assets/script.js
  • assets/img/ (or your own photographs)

Load the fonts and GSAP, then the section script, after the markup:

Code snippet omitted: it ships with the download.

GSAP core is the only dependency; no plugins. Everything outside the <section> in index.html (the page background and body margin) is demo furniture. No build step is needed.

Make it yours

Connect the form

The form ships in demo mode: it validates, then says plainly that nothing was sent. To go live:

  1. Set the form's action to your mailing list provider's subscribe URL.
  2. Remove data-flx-demo from the <form>.
  3. Rename the inputs to the field names your provider expects (email, first_name and short_notice_rooms are placeholders).

By default the script posts the form with fetch and shows the thank-you message when the response is OK, or the error message otherwise. This suits endpoints that accept cross-origin requests (your own backend, a serverless function, or providers with a JSON API). If your provider only accepts an ordinary form post (many embedded signup forms do), add data-flx-submit-mode="native" to the <form>: the script validates, then lets the browser submit normally to your provider's page.

The hidden website input is a honeypot for bots: leave it in place and have your endpoint reject submissions where it is filled. No backend is included. The status messages live in [data-flx-status]; edit their wording there. In the thank-you message, <span data-flx-name> receives the first name, and the surrounding <span data-flx-greet> hides when no name was given. The two validation messages sit on the error element as data-flx-missing and data-flx-invalid.

Letters

Each letter is an <article data-flx-letter> inside [data-flx-letters], and each has an index link in [data-flx-tabs] whose href points at the letter's id. To add a letter, copy a whole <article> and a whole index <li>, give the article a new id and point the new link's href at it. To remove or reorder, delete or move both together. The first letter in the markup opens first, so keep the newest first.

Every letter has three panels, in order: top, middle and bottom. The letter folds along the lines between them, so the three panels always share the letter's height equally. The middle and bottom panels set that height from their content (the tallest letter sets it for all); the photo in the top panel stretches to fill, and the sign-off sits at the foot of the bottom panel. Keep the middle panel's copy to roughly the length of the examples. Inside each letter:

What Where
Letterhead (also printed on the outside when folded) .flx-letter__mark in the top panel
Photograph and caption <figure class="flx-letter__photo"> in the top panel
Title, greeting and opening (one or two paragraphs) .flx-letter__title, .flx-letter__greeting, .flx-letter__body in the middle panel
What else was in the letter, and a postscript .flx-letter__list and .flx-letter__ps in the bottom panel
Sign-off and send date .flx-letter__sign, .flx-letter__meta

Any number of letters works; two to six suit the index. With a single letter the index hides and the letter simply sits open.

Photographs

Every photograph is an ordinary <img> with its own alt. Replace the file or change the src; no animation changes are needed.

Slot File Size Crop control
Letter photographs assets/img/samphire.webp, harbour-breakfast.webp, fireside.webp, geese.webp 1200 x 800 (3:2) or any landscape photo --flx-focus on each <figure>. The photo fills whatever height the top third has left, so its shape follows the letter; --flx-photo-min (default 180px) and --flx-photo-min-narrow (phones, 150px) set its smallest height

The ground behind the letters is CSS only: --flx-ground plus a soft copper pool of light under the letter, both set on .flx__desk::before; retint the pool there with your accent. Letter photos are cropped with object-fit: cover, so portrait photos also work: move --flx-focus to keep the subject in frame.

Brand variables

All colours, fonts and sizes are custom properties on .flx:

Variable Default Role
--flx-ground #140f0b Section background
--flx-ink, --flx-ink-soft #f1e8da, #bfae98 Text on the ground
--flx-line translucent ink Rules on the ground
--flx-accent, --flx-accent-ink #c98d63, #1a110b Copper details, the button and its text
--flx-error #f2a896 Validation messages
--flx-paper, --flx-paper-back #f4ede1, #ebe2d2 Letter front and outside
--flx-paper-ink, --flx-paper-soft, --flx-paper-line dark browns Text and rules on the paper
--flx-font-display, --flx-font-sans Bodoni Moda, Jost Display serif and small caps / interface
--flx-max, --flx-gutter 1320px, fluid Content width and side padding
--flx-letter-width 640px The letter's width
--flx-radius 2px Paper and button corners

A rebrand for a wine estate, for example:

Code snippet omitted: it ships with the download.

Check text contrast after changing colours; the defaults meet WCAG AA for body text on the ground and on the paper.

Behaviour and options

  • data-pace on the section scales every transition: 1 is the default (a letter change takes about three seconds), 1.5 is slower, 0.7 quicker.
  • Choosing the letter a move came from reverses it. Choosing another letter while one is moving hurries the current move and then goes on to the latest choice.
  • If the letters start below the visible screen, the first letter waits folded and opens when it scrolls into view. If it is already visible it is simply open.
  • window.FoldedLetters exposes mount(root), mountAll(scope), destroyAll(scope) and get(root). get(root).select(index) opens a letter from your own code. destroy() reverts the section's own animations, generated back faces, shadows, roles and listeners, and restores the markup; mounting again is safe.

Accessibility and integration

  • The index is a tablist with arrow keys, Home and End, and the letters are tab panels. Letters that are not showing are inert. Pointer, touch and keyboard all use the same controls.
  • With reduced motion the letters switch instantly; changing the preference mid-move settles on the chosen letter.
  • Without JavaScript (or if GSAP fails to load) every letter shows open, one after another, and the index links jump to them; without GSAP the tabs still switch letters, instantly. Without JavaScript the form submits natively to its action, so set one before going live.
  • The form uses visible labels, aria-invalid and aria-describedby for errors, moves focus to the email field when it is invalid, and announces results through a role="status" region.
  • The heading is an h2 and each letter title an h3; change the tags freely, since styles use classes. Section styles guard against host h2, p and similar rules.
  • The section works in narrow columns through container queries: the index becomes a two-by-two set above the letter. It does not pin, scroll-jack or install a smooth scroller.
  • Two instances on one page work independently; duplicate IDs in the second are suffixed automatically.

Dependencies and credits

  • GSAP 3.15 core, from the jsDelivr CDN. Free for commercial use under the GSAP standard licence.
  • Bodoni Moda and Jost from Google Fonts, SIL Open Font License.
  • The photographs are generated concept images made for this section. Ferrow House, its letters and the people in them are fictional sample content; replace them with your own before publishing.

Worked examples, the events and programmatic API, and the class reference ship with the download, alongside the full source.