Skip to content

Demos: a quiet prop for pages that show many at once - #27

Merged
ecropolis merged 1 commit into
mainfrom
claude/demos-quiet-prop
Sep 28, 2026
Merged

ecropolis merged 1 commit into
mainfrom
claude/demos-quiet-prop

Conversation

@ecropolis

Copy link
Copy Markdown
Owner

The contract

Every demo now takes an optional quiet?: boolean (default false), documented beside assetBase in src/components/demos/index.ts and the README:

quiet — the demo is one of many on a page: nothing may open, move, play sound or steal focus by itself. A demo without automatic behaviour ignores it.

An element's own page never passes it, because there the automatic behaviour is the point. The superherotech.ai /elements/ hub will pass it (separate site PR). This gallery's index now passes it too, since it is the same kind of page.

Which demos honour it

modal is the only one. With quiet:

  • demo-modal-offer and demo-modal-exit render with no delay, scroll or exit.
  • Each card gets a plain opener button: "Open it" and "Show the exit modal". The "Forget it, arm it again" buttons go, since nothing is armed.
  • The card labels read "…by itself on its own page, here on a press", and the text inside each modal no longer claims it opened by itself.
  • The quiet copies keep their memory under modal:<id>:quiet. A visitor who opens and closes one on the hub still gets the automatic one on /elements/modal/.

Without quiet, dist/modal/index.html is byte-identical to main.

Reviewed and left alone

Demo Why it stays
toast Every toast comes from a button press. The region is empty and hidden until then.
notice Static inline boxes. Focus moves only after the visitor dismisses one.
announcement-bar Static bars in the flow, not sticky. The countdown is not a live region, and focus moves only on dismiss.
off-canvas Panels open only from their buttons or links. There is no hash auto-open.
cookie-consent The bar shows on load, but inside a sandboxed iframe. It covers only its own frame and never takes focus.
video-player Nothing loads or plays until Play is pressed. The self-hosted clip is preload="none" with no autoplay.
video-gallery Autoplay applies only inside the lightbox the visitor opened.
video-background A muted loop with no sound. The element stops it under reduced motion and on small screens, and it has a pause button.
card-slider, testimonial-carousel, info-circle, hotspot (tour), news-ticker Autoplay moves only inside the demo's own box. Each pauses off-screen, on hover or focus, and in hidden tabs. Each has a pause button and stops under reduced motion. The hotspot tour moves focus only when the visitor's focus is already in its panel.
animated-text, particle-field, animated-background, scroll-reveal, parallax-band Looping or scroll-driven animation, which the elements already handle under reduced motion.
accordion, tabs, tabcordion They scroll or select only when the URL hash names one of their own items. On the hub, the hash is a category id.
stepper, loading, map, menu-button, mega-menu, tags, flip-box, slide-box Every focus move answers the visitor's own click or key.
business-hours Its live status line speaks only when open or closed changes, which is the element's job.
All the others No script-driven behaviour of their own.

One judgment call needs your eye. The contract says "move", and the brief put self-contained autoplay under reduced motion in the fine column. I read "move" as the page or something over it moving, not motion inside the demo's own box. If the hub should also stop the carousels, their demos can drop autoplay under quiet in a follow-up.

Checks

scripts/check-modal-and-bar.mjs has a new stage, 4b. It reads the gallery (ModalDemo with quiet) and /modal/ (without it):

  • With quiet, it asserts that no data-md config carries a delay, a scroll or exit. The two opener buttons must exist with their labels and type="button", and the memory keys must differ from the element page's.
  • Without quiet, it asserts that both automatic configs are exactly as before and that the "Forget it" buttons are present.
  • Two planted faults must be caught: the element page passed off as quiet, and a quiet page missing its exit opener.

The full npm run check chain is green.

I also ran headless Chrome against the built gallery. After 22 seconds, a scroll past half the page and an exit-intent attempt, nothing had opened. Both buttons opened their modals and focus returned to the opener. On /modal/, the offer still opened by itself on scroll.

The Modal element itself (src/library/modal/Modal.astro) is untouched.

🤖 Generated with Claude Code

`quiet` — the demo is one of many on a page: nothing may open, move, play
sound or steal focus by itself. A demo without automatic behaviour ignores it.

ModalDemo honours it: the offer (delay/scroll) and exit-intent modals lose
their automatic config, each card gets an opener button, and the quiet copies
remember under their own key so a press on the hub never hides the automatic
ones on /modal/. Without quiet the render is byte-identical.

The gallery index passes quiet to every demo. check-modal-and-bar pins both
renders, with two planted faults.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ecropolis
ecropolis merged commit cb4d983 into main Sep 28, 2026
2 checks passed
@ecropolis
ecropolis deleted the claude/demos-quiet-prop branch September 28, 2026 03:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant