CSP + Alpine x-transition: modals need explicit CSS transitions

On this page

Overview

Under the strict Content Security Policy (style-src 'self'), canopy-web cannot use inline style= attributes. Alpine’s x-transition directive needs a real CSS transition property on the element to drive its animation. When inline styles were externalised for CSP, the implicit transition timing the browser previously supplied was lost — so x-transition waits forever for a transitionend event that never fires, and Playwright’s stability check times out clicking buttons inside the modal. This runbook records the hazard so a future CSP refactor doesn’t silently reintroduce it.

Symptom

A Playwright test fails with Timeout waiting for element to be visible, enabled, and stable on a button inside a modal that uses x-show + x-transition. First known consumer: the deny modal in tests/e2e/specs/applications.spec.ts. Alpine leaves the modal in a never-resolving "in-transition" state; Playwright’s 500ms layout-quiescence check intermittently lands there and times out on submitBtn.click().

Root cause

x-transition with no CSS transition property → no transitionend event → Alpine never completes the transition. Commit b4ee102 ("fix: strict CSP") refactored inline style= attributes into utility classes to satisfy style-src 'self'. Structurally correct for CSP, but it dropped the implicit transition timing the inline styles carried. The bug was latent until the Stage 1 Orchard CSS work changed the resolution timing of the modal dialog’s background: var(--orchard-surface) (served from the dynamic /theme.css endpoint).

Fix (load-bearing CSS)

services/canopy-web/static/css/canopy-web.css.u-modal-overlay and .u-modal-dialog MUST carry explicit transition properties:

.u-modal-overlay { /* … */ transition: opacity 150ms ease-in-out; }
.u-modal-dialog  { /* … */ transition: transform 150ms ease-in-out; }

A /* … load-bearing … */ comment sits above these rules so a future refactor doesn’t strip them. Fixed in Stage 3 MR1 (closes #511) via these four lines.

Prevention checklist

  • When any Playwright test times out on "visible, enabled, and stable" for a button inside an x-show + x-transition modal: confirm the modal’s CSS class carries an explicit transition.

  • When a CSP / inline-style refactor lands on canopy-web: grep for x-transition in the touched templates and verify the corresponding utility classes still carry transition properties.

  • The same hazard applies to any Alpine-driven animation that was previously implicit via inline styles.

  • services/canopy-web/templates/applications/process.html — deny modal (first known consumer).

  • services/canopy-web/templates/base.html — loads alpine-csp.min.js (since b4ee102).

  • tests/e2e/specs/applications.spec.ts — the spec that surfaced the regression.

  • Configuration Reference — the BFF Content Security Policy.

Edit this page · default