Open Source

서식이 적용된 text에 tab 삽입 시 연속적인 서식 적용 허용

2026년 2월 19일

Lexical 에디터에서 서식이 적용된 텍스트 사이에 Tab을 삽입했을 때, 이후 입력되는 텍스트의 서식이 유실되는 문제를 분석하고 해결한 과정을 공유합니다.

문제 상황

서식(예: Bold)이 적용된 텍스트 한가운데에 Tab을 삽입하고, 그 Tab 사이나 직후에 텍스트를 입력할 때 기존 서식이 이어지지 않는 현상이 발생했습니다.

재현 단계

  1. 에디터에 "hello"를 입력하고 Bold 서식을 적용합니다.
  2. 커서를 "he"와 "llo" 사이로 이동합니다.
  3. Tab 키를 두 번 누릅니다.
  4. 두 개의 Tab 사이로 커서를 이동합니다.
  5. 새로운 문자를 입력합니다.

결과: Tab 사이에 입력된 문자에는 Bold 서식이 적용되지 않고 일반 텍스트로 입력됩니다.


원인 분석

Lexical에서 새로운 텍스트가 입력될 때의 서식은 보통 이전 노드의 format 정보를 기반으로 결정됩니다. 하지만 기존의 TabNode 삽입 로직을 살펴보면 서식 정보를 고려하지 않고 단순히 노드만 생성하고 있었습니다.

기존 코드 분석

editor.registerCommand(
  INSERT_TAB_COMMAND,
  () => {
    // 단순히 TabNode를 생성하여 삽입함
    $insertNodes([$createTabNode()]);
    return true;
  },
  COMMAND_PRIORITY_EDITOR,
),

TabNode가 삽입될 때 현재 Selection이 가지고 있는 format이나 style 정보를 물려받지 않기 때문에, Tab 노드 사이나 이후에 입력되는 텍스트가 참조할 서식 기준이 사라지게 되는 것이 원인이었습니다.


해결 방법

변경 사항

editor.registerCommand(
  INSERT_TAB_COMMAND,
  () => {
    const tabNode = $createTabNode();
    const selection = $getSelection();

    if ($isRangeSelection(selection)) {
      // 현재 selection의 format과 style을 TabNode에 동기화
      tabNode.setFormat(selection.format);
      tabNode.setStyle(selection.style);
    }

    $insertNodes([tabNode]);
    return true;
  },
  COMMAND_PRIORITY_EDITOR,
),

INSERT_TAB_COMMAND가 실행될 때 현재 사용자의 Selection 상태를 확인하고, 만약 서식 정보가 있다면 이를 생성되는 TabNode에도 명시적으로 설정해주도록 수정했습니다. 이렇게 TabNode 자체에 서식 정보를 저장하게 함으로써, 해당 위치에서 텍스트 입력이 일어날 때 에디터가 올바른 서식을 적용할 수 있도록 개선했습니다.

playground


추가 논의: LineBreakNode의 한계

이번 문제를 해결하면서 LineBreakNode에서도 동일한 현상이 발생하는 것을 확인했습니다. 하지만 LineBreakNodeTextNode가 아닌 LexicalNode를 직접 상속받는 구조여서, 현재 Lexical 아키텍처상 format이나 style 필드를 가질 수 없는 제약이 있습니다.

이 부분은 다른 해결 방법이 요구되어 별도의 논의가 필요한 과제로 남겨두었습니다.