Skip to content

[lexical-extension][lexical-rich-text][lexical-react] Feature: Support configuration of indentable nodes#8122

Merged
etrepum merged 7 commits intofacebook:mainfrom
levensta:nodes-for-tabindentation-plugin
Feb 10, 2026
Merged

[lexical-extension][lexical-rich-text][lexical-react] Feature: Support configuration of indentable nodes#8122
etrepum merged 7 commits intofacebook:mainfrom
levensta:nodes-for-tabindentation-plugin

Conversation

@levensta
Copy link
Copy Markdown
Contributor

@levensta levensta commented Feb 8, 2026

Breaking Change

TabIndentationExtension and TabIndentationPlugin now enforce max indentation level on a per-block basis. Previously, any block at max indentation in the selection would prevent all indentation of the selection.

Description

I added a new option to the TabIndentation plugin and extension. The essence of the feature is to provide an interface for a limited selection of classes that can be indented by pressing Tab.

Although it is possible to override the canIndent method for classes that do not need indents, this generates a lot of boilerplate code. For example, in a real-world case, you may need to be able to set nested lists using Tab, but not set indents for all other elements. To do this, you would need to extend each class used from lexical to override only one method, canIndent With the new option in the plugin, this task is simplified

It is now also possible to set indents for each node within a selection independently of each other. If one of the nodes has the maximum indent value, the indent will be added to the others. Previously, Tab did not work for any nodes if there was at least one maximum value among the nodes.

Test plan

Before

All elements can be indented. If one of the selected nodes has the maximum indentation, no indentation will be set for the other elements.

Screen.Recording.2026-02-08.at.17.50.57.mov

After

All elements can be indented. Nodes with maximum indentation are ignored, while the rest elements are indented

Screen.Recording.2026-02-08.at.17.53.12.mov

If indents are only needed for specific nodes. For example, for lists

<TabIndentationPlugin maxIndent={7} $canIndent={$isListItemNode} />
Screen.Recording.2026-02-08.at.03.14.30.mov

@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 Feb 8, 2026
@vercel
Copy link
Copy Markdown

vercel bot commented Feb 8, 2026

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

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

Request Review

Copy link
Copy Markdown
Collaborator

@etrepum etrepum left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest an even simpler approach where something like $canIndent: (node: ElementNode) => boolean is the configuration with a default implementation of (node) => node.canIndent() and then the user can make any possible override of behavior from there.

@levensta
Copy link
Copy Markdown
Contributor Author

levensta commented Feb 8, 2026

I would suggest an even simpler approach where something like $canIndent: (node: ElementNode) => boolean is the configuration with a default implementation of (node) => node.canIndent() and then the user can make any possible override of behavior from there.

Good idea. I did it and also extended the current e2e test for indentation, since now the maximum indentation level can be set by selected nodes independently of each other. I think it looks expected and natural, watch the demo video in the updated description

@etrepum etrepum added the extended-tests Run extended e2e tests on a PR label Feb 8, 2026
@etrepum etrepum changed the title [lexical-react] Feature: Support configuration of indentable nodes [lexical-extension][lexical-rich-text][lexical-react] Feature: Support configuration of indentable nodes Feb 8, 2026
@etrepum
Copy link
Copy Markdown
Collaborator

etrepum commented Feb 8, 2026

I think the integration tests are failing because this introduced a circular dependency from extension -> rich-text -> dragon -> extension

@levensta
Copy link
Copy Markdown
Contributor Author

levensta commented Feb 8, 2026

I think the integration tests are failing because this introduced a circular dependency from extension -> rich-text -> dragon -> extension

thanks, fixed

Copy link
Copy Markdown
Collaborator

@etrepum etrepum left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you update the e2e test to preserve the existing tests? It's difficult to see if this is backwards compatible or not because it looks like the tests have also changed in-place.

@levensta
Copy link
Copy Markdown
Contributor Author

levensta commented Feb 9, 2026

Can you update the e2e test to preserve the existing tests? It's difficult to see if this is backwards compatible or not because it looks like the tests have also changed in-place.

The test had to be changed anyway because it checked the old behavior of the plugin and failed after the changes. Previously, it was expected that none of the elements would set indentation if at least one of them reached the maximum value

Maybe this workaround will help you 😅
Try copying the string from assertHTML and pasting it as text/html into the preview environment.

console code
async function copyHtmlToClipboard(html) {
  const blob = new Blob([html], { type: "text/html" });
  const data = new ClipboardItem({ "text/html": blob });

  await navigator.clipboard.write([data]);
  console.log("HTML сopied as text/html");
}


// paste html here
const html = `

`;

// focus on the document during the timer
setTimeout(() => copyHtmlToClipboard(html), 1500); 

@etrepum
Copy link
Copy Markdown
Collaborator

etrepum commented Feb 9, 2026

My point here is that we should verify that if you don’t add any new settings then the behavior shouldn’t change.

@levensta
Copy link
Copy Markdown
Contributor Author

levensta commented Feb 9, 2026

My point here is that we should verify that if you don’t add any new settings then the behavior shouldn’t change.

That's the point. Without changing the settings, the test fails with an error because it checked different behavior.

https://github.com/facebook/lexical/actions/runs/21797687397/job/62887841955#step:11:293

I can revert to the previous behavior and add a check for the existence of the maximum indent value among the selected elements so that the test does not fail, but I think from a UX perspective it is better to give the user the ability to indent all remaining nodes than not to give it at all.

etrepum
etrepum previously approved these changes Feb 10, 2026
Copy link
Copy Markdown
Collaborator

@etrepum etrepum left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that behavior probably makes sense, but I think the PR description should cover this change in behavior before this is merged.

@etrepum
Copy link
Copy Markdown
Collaborator

etrepum commented Feb 10, 2026

I think this test might need to be looked at:

[chromium] › packages/lexical-playground/__tests__/e2e/Autocomplete.spec.mjs:31:3 › Autocomplete › Can autocomplete a word 

@etrepum etrepum added this pull request to the merge queue Feb 10, 2026
Merged via the queue into facebook:main with commit 36b8872 Feb 10, 2026
39 checks passed
@levensta levensta deleted the nodes-for-tabindentation-plugin branch February 10, 2026 20:15
@etrepum etrepum mentioned this pull request Feb 25, 2026
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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants