저희는 노션과 같은 직관적이고 자연스러운 온라인 블록 기반 텍스트 에디터를 개발중입니다.
HTML의 contentEditable
속성을 활용해 구현하기로 결정했지만, 예상치 못한 여러 가지 문제점이 발생했습니다.
그래서 이 글을 통해 위 상황에서 겪은 문제를 해결해 나가는 과정을 공유하고자 합니다.
처음에는 textarea
를 사용하여 블록 단위의 입력을 구현하려 했으나, 블록 내 개별 항목들을 유연하게 다루기 어려운 문제가 있었습니다. 이를 해결하기 위해 contentEditable
을 활용하는 방법을 알게 되었고, 보다 유연한 구성과 블록 기반의 에디터 구조를 구현할 수 있어 contentEditable
로 변경하게 되었습니다.
하지만, 이 과정에서 여러 가지 문제점이 발생했습니다.
contentEditable을 사용할 때, 입력 시 커서가 자동으로 맨 앞으로 이동하는 현상이 발생했습니다.
입력을 할때마다 상태가 바뀌어 리렌더링이 발생하고, 이때 다시 포커스를 하게 되면서 커서의 위치가 해당 블록의 맨 앞으로 다시 위치하게 된다고 생각했습니다.
이를 해결하기 위해 입력 시마다 매번 커서의 위치를 저장한 후, 렌더링 이후 강제로 커서를 원래 위치로 복구하는 방식으로 해결하고자 하였습니다.
const handleInput = () => {
const selection = window.getSelection();
const range = selection?.getRangeAt(0);
const cursorPosition = range?.startOffset || 0;
setTimeout(() => {
const newRange = document.createRange();
const newSelection = window.getSelection();
newRange.setStart(restoredBlock.childNodes[0] || restoredBlock, cursorPosition);
newRange.collapse(true);
newSelection?.removeAllRanges();
newSelection?.addRange(newRange);
}
}, 0);
};
range.startOffset
을 통해 저장setTimeout()
을 사용하여 커서를 원래 위치로 복구