Skip to content

feat: inline (non-modal, non-top-layer) mode for overlays, for theme previews and showcases #563

Closed

Description

@mvilacad

Theme previews and showcases need to render the real overlays inside a themed island. Today they cannot: a modal Dialog is moved to <body> and shown with showModal(), and menus, popovers and tooltips use popover="manual" + showPopover(). Both go to the browser top layer, so they leave the island and lose its data-preset / data-theme-scope tokens. The Theme Studio (#560) therefore previews overlays as static copies.

Ask

An opt-in inline mode: the overlay renders where it is declared, in normal flow or absolutely positioned inside a position: relative host, never in the top layer.

  • Dialog, Sheet, Drawer, AlertDialog: inline renders the panel as a non-modal <dialog open> (show()), with a faux scrim drawn by the host. No inert page, scroll lock or focus trap.
  • FloatingLayer (so DropdownMenu, Popover, Tooltip, HoverCard, ContextMenu): inline skips popover/showPopover(), and positions against its anchor with position: absolute inside the host.
  • Toaster: inline positions absolute in its container instead of fixed.
  • Shared plumbing in primitives/layer.ts: an inline layer option that does not push onto the global stack (no Escape or outside-press ownership), so an inline overlay can never steal input from a real one.

Acceptance

  • Test first: a harness renders each overlay inline inside an element with data-preset="violet" and asserts the overlay's computed --ca-brand-main is the island's, not the page's. It fails on current code.
  • A real modal opened on the same page still owns Escape and inertness while inline overlays are present.
  • Docs section on theme previews, docs/css-api.md updated, axe clean in both modes.

Status

Blocks "tweakcn parity done". The Theme Studio (#560, PR #562) previews overlays as static copies, labelled as such in the UI. Real Dialog, Menu and Toast inside a themed island is the last gap against the owner's bar, so parity is not done until this lands.

Verification

This changes the shared layer engine (primitives/layer.ts: the stack, Escape and outside-press ownership, modal inertness, focus trap, scroll lock, positioning). It must pass the full overlay and layer suites (primitives/layer, Dialog, Sheet, Drawer, AlertDialog, Popover, DropdownMenu, Tooltip, HoverCard, ContextMenu, Toaster, nested layers) and the route sweep (routes.a11y, overlays.a11y, dialog-modal, scroll-lock), not only the studio tests.

Activity

  1. added
    enhancementNew feature or request
    area:componentsSvelte components and primitives
    in progressSomeone is working on it (see the linked draft PR)
    on Oct 25, 2026
  2. self-assigned this
    on Oct 25, 2026
  3. mvilacad commented on Oct 25, 2026

    @mvilacad
    ContributorAuthor

    Working on this in #608 (draft). Branch feat/563-feat-inline-non-modal-non-top. Regression test first, then the fix.

  4. added a commit that references this issue on Oct 25, 2026
    4bb8e72
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:componentsSvelte components and primitivesenhancementNew feature or requestin progressSomeone is working on it (see the linked draft PR)

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions