Safari: selection becomes null when editor blurs
In Safari the editor selection becomes null when the editor is blurred. However in Chrome & Firefox, the selection is preserved when the editor blurs.
Chrome
https://user-images.githubusercontent.com/25709855/125637734-aa1621da-41dc-4020-820b-4f1eaf30ac64.mp4
Firefox
https://user-images.githubusercontent.com/25709855/125637787-15b43f99-af22-4fa5-b54e-ecef64af6f00.mp4
Safari
https://user-images.githubusercontent.com/25709855/125637827-b2c47db7-9338-4076-b825-8f3c2b02f62c.mp4
Steps
- Go to Sandbox
- Select some text from the editor.
- Click the button
Bold. To make the text bold. - Works in Chrome & Firefox. Fails in Safari.
Expectation
Expected behavior is get similar output for editor.selection across browsers when the editor blurs. In this case the selection is preserved for Chrome & Firefox but becomes null in Safari.
Environment
- Slate Version: [0.63.0]
- Slate React Version: [0.65.2]
- Operating System: [macOS]
- Browser: [Chrome, Safari,Firefox]
Cause of this issue can be #4324, where to fix a backward typing bug in Safari. Safari specific code was added to make sure the selection becomes null when editor is blurred.
I think this has caused an issue with our BalloonToolbar plugin. It is designed to stay open as long as the editor has selection but a bug was reported after we upgraded where it closes in Safari when the editor blurs.
@clauderic do you think we could come up with another solution for #4324? Happy to help if we can.
@clauderic I can confirm that undoing the change in #4324 does fix this issue. ~~Strangely I also can't replicate the backwards typing bug, where there particular circumstances in which you got it or was it consistent?~~ I get around the backwards typing bug by calling ReactEditor.focus(editor) in my toggleMark function:
export function toggleMark(editor: Editor, format: INLINE_TYPE): void {
const isActive = isMarkActive(editor, format);
if (isActive) {
Editor.removeMark(editor, format);
} else {
Editor.addMark(editor, format, true);
}
ReactEditor.focus(editor);
}
The backward typing bug can be reproduced consistently in Safari if you programatically blur the editor. Try adding a toolbar button that blurs the editor when clicked to the RichText example https://github.com/ianstormtaylor/slate/blob/main/site/examples/richtext.tsx:
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
<Toolbar>
<MarkButton format="bold" icon="format_bold" />
// ...
+ <button onClick={() => ReactEditor.blur(editor)}>Blur</button>
</Toolbar>
https://user-images.githubusercontent.com/1416436/121074881-75ce0f00-c7a2-11eb-94e7-9f3fb3356943.mp4
As far as toolbar buttons go, the approach I would recommend is to prevent the default browser behaviour (blurring the contenteditable element) on pointer down:
function ToolbarButton() {
return <button onPointerDown={preventDefault} />
}
function preventDefault(event) {
event.preventDefault();
}
Thanks @clauderic, unfortunately the preventDefault() trick doesn't quite work as expected in Safari and often returns focus to the wrong place, see gif below, whereas ReactEditor.focus(editor) acts as you'd expect.

@jamestowers I am also using React.focusEditor to get around the backward typings bug in Safari. But I have to use an older version of slate-react v0.65.0 to get similar behaviour in all browsers.
@Harsh1796 is the older version to prevent the null selection issue you first posted above, or are there other issues too?
I may be missing something but I feel the downsides of the changes in #4324 are bigger than the those of adding ReactEditor.focus(editor) as #4324 is wiping out a whole browser
Does anyone know the root cause of #4324? I expect it's a safari quirk? I'd be keen to work on an alternative solution if we had an idea of where to look.
@jamestowers I am using an older version to prevent the null selection issue and maintain a similar behaviour in all browsers for my use case.
Running into the same issue today, I have menu components that live outside of the Slate editor, I want to bring back the focus to the editor after the user clicks something in the menus, in Chrome caret position is restored properly but not in Safari. Has anybody found a workaround for this?