Skip to content

Move custom element display rules from JS to CSS to prevent CLS#2400

Open
joshhanley wants to merge 1 commit intomainfrom
josh/fix-custom-element-cls
Open

Move custom element display rules from JS to CSS to prevent CLS#2400
joshhanley wants to merge 1 commit intomainfrom
josh/fix-custom-element-cls

Conversation

@joshhanley
Copy link
Member

The Scenario

When using Flux custom elements like <flux:description>, <flux:label>, <flux:checkbox>, or <flux:switch>, there is a visible layout shift (CLS) on first paint. Elements briefly render as display: inline (the browser default for unknown elements), then snap to their correct display value once JavaScript executes.

This is most noticeable on elements visible at first paint — particularly ui-description with longer text that wraps differently at inline vs block:

<flux:field>
    <flux:label>Email</flux:label>
    <flux:input name="email" />
    <flux:description>Enter your email address. But this is more noticeable if you have a really long helper text that wraps a couple times.</flux:description>
</flux:field>

The Problem

Display values for ~30 custom elements are set exclusively at runtime via JavaScript inject() calls — one per component file (e.g. js/field.js, js/select.js, js/checkbox.js). The inject() function uses document.adoptedStyleSheets to create CSS rules dynamically:

inject(({ css }) => css`ui-description { display: block; }`)
inject(({ css }) => css`ui-checkbox { display: inline-block; user-select: none; }`)
inject(({ css }) => css`ui-switch { display: inline-block; user-select: none; }`)
// ~25 more...

Until JS executes, browsers render these unknown elements as display: inline, causing the layout shift. Only ui-button had a pre-existing CSS rule in flux.css.

The Solution

Move all custom element display rules into flux.css inside an @layer base block, so they apply from first paint while still allowing Tailwind utility classes to override them.

This PR adds the CSS rules. The corresponding inject() calls are removed from the JS source files in a companion PR (livewire/flux-pro#446).

Fixes #2394

Add display rules for all custom elements (`ui-select`,
`ui-description`, `ui-checkbox`, `ui-switch`, `ui-radio`, etc.) to
`flux.css` inside `@layer base`. Previously these were only set at
runtime via JS `inject()` calls, causing layout shift between CSS
loading and JS execution.
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.

Custom element display rules should be in CSS, not JS (causes CLS)

1 participant