Skip to content

[lexical] Bug Fix: Resolve --lexical-indent-base-value via CSS var() instead of pre-computing in JS#8466

Merged
etrepum merged 1 commit into
facebook:mainfrom
mayrang:fix/element-indent-css-variable
May 6, 2026
Merged

[lexical] Bug Fix: Resolve --lexical-indent-base-value via CSS var() instead of pre-computing in JS#8466
etrepum merged 1 commit into
facebook:mainfrom
mayrang:fix/element-indent-css-variable

Conversation

@mayrang

@mayrang mayrang commented May 5, 2026

Copy link
Copy Markdown
Contributor

Description

setElementIndent read --lexical-indent-base-value via getComputedStyle(activeEditor._rootElement || dom) and substituted the resolved value into a calc(...) expression on padding-inline-start. This was brittle in two ways: getComputedStyle only sees the CSS variable if it cascades to _rootElement or dom, so themes that put the variable on the indent class itself (or any selector below the root) silently fell back to DEFAULT_INDENT_VALUE (40px); and when called from $createNode before the new DOM is attached to its parent, no cascade has happened yet, so even the same selector layout could miss the variable depending on timing. The reported symptom was that copy/pasted paragraphs ignored a custom --lexical-indent-base-value setting and used 40px instead.

setElementIndent now writes padding-inline-start: calc(N * var(--lexical-indent-base-value, 40px)) directly. The CSS variable reference is preserved in the inline style, so the browser resolves it at cascade time using whichever scope defines the variable. Mount timing no longer matters, and getComputedStyle (which forces layout) is no longer called per indent change. This is the approach etrepum suggested in the issue thread.

Existing test snapshots that asserted the old pre-resolved string (calc(40px), calc(80px), etc.) were updated to the new calc(N * var(--..., 40px)) form. Two regression tests were added in LexicalReconciler.test.ts covering the var() output and the indent=0 padding clear.

Closes #7730

Test plan

  • pnpm tsc clean.
  • pnpm test-unit — 117 files / 3038 pass (was 3036 before, +2 new regression tests in LexicalReconciler.test.ts).
  • Manual playground reproduction (Chromium): with --lexical-indent-base-value defined on the indent class only, paragraphs lost their custom indent value before the fix; after the fix the value cascades correctly.
  • e2e suite: snapshot updates are mechanical, deferring to CI in real browsers.
…instead of pre-computing in JS

## Description

`setElementIndent` read `--lexical-indent-base-value` via `getComputedStyle(activeEditor._rootElement || dom)` and substituted the resolved value into a `calc(...)` expression on `padding-inline-start`. This is brittle in two ways: (a) `getComputedStyle` only sees the CSS variable if it cascades to `_rootElement` or `dom`, so themes that put the variable on the indent class itself (or any selector below the root) silently fell back to `DEFAULT_INDENT_VALUE` (`40px`); (b) when called from `$createNode` before the new DOM is attached to its parent, no cascade has happened yet, so even the same selector layout could miss the variable depending on timing. The reported symptom was that copy/pasted paragraphs ignored a custom `--lexical-indent-base-value` setting and used `40px` instead.

## Fix

`setElementIndent` now writes `padding-inline-start: calc(N * var(--lexical-indent-base-value, 40px))` directly. The CSS variable reference is preserved in the inline style, so the browser resolves it at cascade time using whichever scope defines the variable. Mount timing no longer matters, and `getComputedStyle` (which forces layout) is no longer called per indent change.

Existing test snapshots that asserted the old pre-resolved string (`calc(40px)`, `calc(80px)`, etc.) were updated to the new `calc(N * var(--..., 40px))` form. Two regression tests were added in `LexicalReconciler.test.ts` covering the var() output and the indent=0 padding clear.

Closes facebook#7730.

## Test plan

- [x] `pnpm tsc` clean
- [x] `pnpm test-unit` — 117 files / 3038 pass (was 3036, +2 new)
- [ ] `pnpm test-e2e-chromium` — defer to CI (mechanical snapshot update; CI verifies in real browsers)
@vercel

vercel Bot commented May 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
lexical Ready Ready Preview, Comment May 5, 2026 8:33pm
lexical-playground Ready Ready Preview, Comment May 5, 2026 8:33pm

Request Review

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label May 5, 2026
@etrepum etrepum added the extended-tests Run extended e2e tests on a PR label May 5, 2026
@etrepum etrepum added this pull request to the merge queue May 6, 2026
Merged via the queue into facebook:main with commit 5c0f31a May 6, 2026
42 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. extended-tests Run extended e2e tests on a PR

2 participants