
Rich text editor with efficient long-form rendering, custom spans, per-edit events, exposed scroll state, spell‑checking and built-in find/replace for advanced text editing.
Compose has been missing a Rich Text Editor since its inception. I've taken a crack at this previously, as have others.
However, they have all suffered from fundamental limitations in BasicTextField, the foundation of
all text entry in Compose.
This project is an attempt to re-implement text entry from scratch to finally have a solution to the various problems.
I've been trying to implement a spell checking text
field in Compose, and keep running up against
the limitations of BasicTextField. Pretty much out of options, I decided to see what it might take
to replace BasicTextField with something that solved all of my needs.
And now, it's working, and at this point, working pretty well.
<u>), highlight (==text== or <mark>), colour and size (<span style>)# , - , **bold**)You can Give it a try here, or browse the API reference & recipes.
RichTextView publish their text, selection,
links and clipboard actions as BasicTextField does, with character bounds on
Android and iOS.rememberSaveableTextEditorState: the document, caret, selection and scroll survive
configuration changes and process death (the undo history does not).TextEditorState(initialText): a view model can create, load and edit the document
outside composition, and hand it to the editor later.softWrap = false) for code: each line one row,
the editor scrolling sideways.| Platform | Status |
|---|---|
| Desktop (JVM) | Supported |
| Android | Supported |
| iOS | Beta: typing, autocorrect, CJK composition, the edit menu, loupe and touch handles |
| WASM | Beta: typing, IME composition, the rich clipboard and drag and drop |
Text Editor:
implementation("com.darkrockstudios:composetexteditor:3.0.3")
Markdown addon, to use the editor as a markdown editor (state.withMarkdown()):
implementation("com.darkrockstudios:composetexteditor-markdown:3.0.3")
Spell Checking addon:
implementation("com.darkrockstudios:composetexteditor-spellcheck:3.0.3")
Find & Replace addon:
implementation("com.darkrockstudios:composetexteditor-find:3.0.3")
Or take the BOM and leave the versions off the modules, so they always match:
implementation(platform("com.darkrockstudios:composetexteditor-bom:3.0.3")
implementation("com.darkrockstudios:composetexteditor")
implementation("com.darkrockstudios:composetexteditor-markdown")
implementation("com.darkrockstudios:composetexteditor-spellcheck")
implementation("com.darkrockstudios:composetexteditor-find")Upgrading from 2.x (markdown as its own module, decoration layers, shortcuts matched on the keyboard layout): see docs/MIGRATION.md. How the editor is built is in docs/ARCHITECTURE.md, and how it is tested in docs/TESTING.md.
On iOS, host the Compose view with .ignoresSafeArea(.keyboard) in SwiftUI, as the
Compose Multiplatform template does. The editor keeps its caret above the keyboard itself;
letting SwiftUI shrink the view as well moves the content twice.
On Android, declare android:windowSoftInputMode="adjustResize" on the activity, as
Compose apps should; otherwise Android also pans the whole window to the caret. The
editor keeps its caret in view whether the host pads it by the keyboard's inset
(imePadding) or lets the keyboard cover it. TextEditorState.keyboardSettings asks the
keyboard for its capitalisation, autocorrect, layout and action key; an editor for code
would turn capitals and autocorrect off. Android, iOS and the web honour it; the web
ignores autocorrect.
I don't know. Maybe. It might not be a permanent solution.
BasicTextField2's new state based approach and gap-buffer has reached maturity and includes a lot of what I would need
to replace this, but still cannot handle rich text rendering.
So until that is solved, this is the only solution that I am aware of that ticks every box.
Compose has been missing a Rich Text Editor since its inception. I've taken a crack at this previously, as have others.
However, they have all suffered from fundamental limitations in BasicTextField, the foundation of
all text entry in Compose.
This project is an attempt to re-implement text entry from scratch to finally have a solution to the various problems.
I've been trying to implement a spell checking text
field in Compose, and keep running up against
the limitations of BasicTextField. Pretty much out of options, I decided to see what it might take
to replace BasicTextField with something that solved all of my needs.
And now, it's working, and at this point, working pretty well.
<u>), highlight (==text== or <mark>), colour and size (<span style>)# , - , **bold**)You can Give it a try here, or browse the API reference & recipes.
RichTextView publish their text, selection,
links and clipboard actions as BasicTextField does, with character bounds on
Android and iOS.rememberSaveableTextEditorState: the document, caret, selection and scroll survive
configuration changes and process death (the undo history does not).TextEditorState(initialText): a view model can create, load and edit the document
outside composition, and hand it to the editor later.softWrap = false) for code: each line one row,
the editor scrolling sideways.| Platform | Status |
|---|---|
| Desktop (JVM) | Supported |
| Android | Supported |
| iOS | Beta: typing, autocorrect, CJK composition, the edit menu, loupe and touch handles |
| WASM | Beta: typing, IME composition, the rich clipboard and drag and drop |
Text Editor:
implementation("com.darkrockstudios:composetexteditor:3.0.3")
Markdown addon, to use the editor as a markdown editor (state.withMarkdown()):
implementation("com.darkrockstudios:composetexteditor-markdown:3.0.3")
Spell Checking addon:
implementation("com.darkrockstudios:composetexteditor-spellcheck:3.0.3")
Find & Replace addon:
implementation("com.darkrockstudios:composetexteditor-find:3.0.3")
Or take the BOM and leave the versions off the modules, so they always match:
implementation(platform("com.darkrockstudios:composetexteditor-bom:3.0.3")
implementation("com.darkrockstudios:composetexteditor")
implementation("com.darkrockstudios:composetexteditor-markdown")
implementation("com.darkrockstudios:composetexteditor-spellcheck")
implementation("com.darkrockstudios:composetexteditor-find")Upgrading from 2.x (markdown as its own module, decoration layers, shortcuts matched on the keyboard layout): see docs/MIGRATION.md. How the editor is built is in docs/ARCHITECTURE.md, and how it is tested in docs/TESTING.md.
On iOS, host the Compose view with .ignoresSafeArea(.keyboard) in SwiftUI, as the
Compose Multiplatform template does. The editor keeps its caret above the keyboard itself;
letting SwiftUI shrink the view as well moves the content twice.
On Android, declare android:windowSoftInputMode="adjustResize" on the activity, as
Compose apps should; otherwise Android also pans the whole window to the caret. The
editor keeps its caret in view whether the host pads it by the keyboard's inset
(imePadding) or lets the keyboard cover it. TextEditorState.keyboardSettings asks the
keyboard for its capitalisation, autocorrect, layout and action key; an editor for code
would turn capitals and autocorrect off. Android, iOS and the web honour it; the web
ignores autocorrect.
I don't know. Maybe. It might not be a permanent solution.
BasicTextField2's new state based approach and gap-buffer has reached maturity and includes a lot of what I would need
to replace this, but still cannot handle rich text rendering.
So until that is solved, this is the only solution that I am aware of that ticks every box.