Native all the way, until you need text

justsitandgrin.im

338 points by dive 9 hours ago


msephton - 6 hours ago

I recently launched a text editor for iOS that uses TextKit 2 and is highly performant with files of 5,000 lines (I tested with Moby Dick from Project Gutenberg). I made it between Aug 2025 and Apr 2026, development is ongoing.

Every keystroke is restyled in under 8ms: no debouncing, no delayed rendering. 20 rapid keystrokes are processed in 150ms with full restyling after each one.

Tag and boolean searches complete in under 20ms. Visible-range rendering is 25x faster than full-document styling. 120Hz screen refresh supported.

App file size was 722 KB for 1.0, and 1.1 with more features is looking like ~950 KB.

If I can do it on iOS then it's must be 10x easier on macOS.

https://www.gingerbeardman.com/apps/papertrail/

pornel - 8 hours ago

Usually performance was the reason for using native APIs rather than web views, but this doesn't seem to be true any more.

Browser rendering engines are pretty mature at this point, with significant GPU acceleration, and over a decade stress-testing by bloated web apps.

Meanwhile SwiftUI doesn't feel particularly fast. Apple's latest and greatest rewrite of System Preferences has dumbed down the UI to mostly rows of checkboxes, and yet switching between sections can lag worse than loading web pages from us-east-1.

andix - 16 minutes ago

For rich text rendering HTML and browsers are simply the best. Highly optimized. For simple layouts (like rendered markdown) they are incredibly fast.

On most platforms it's quite easy to embed a browser in a frame (show a changelog, an email, or a page of interactive charts). With a few tweaks this can feel completely seamless.

It becomes really painful (or impossible) though, if you need those complex text rendering on multiple places scattered over the native UI. Or if the native UI should interact with the HTML somehow (drop-downs, edit text, add native controls inside html).

Thats why everyone is building Electron/etc apps.

Wowfunhappy - 8 hours ago

If you're on macOS, WebKit is a native OS framework. Using WebKit to render Markdown seems completely appropriate.

Now, if you're rendering everything with WebKit, that's ridiculous, in the same way rendering everything with PDFKit would be ridiculous. But for a Markdown view, WebKit seems like a logical choice. There's no need to subsequently flip the table and replace everything with a Chromium web app.

lenkite - 8 hours ago

> But I still cannot make a simple thing work properly: a chat with Markdown & the ability to select a whole message.

Sorry, sounds like bullsh_t. One can leverage mature markdown renderers in SwiftUI. See https://github.com/gonzalezreal/swift-markdown-ui and its next gen replacement https://github.com/gonzalezreal/textual .

Used these myself and had no issues. And I am a moron who doesn't like Swift or SwiftUI - preferred Objective-C, but still managed to do this, without any LLM help.

rTX5CMRXIfFG - 8 hours ago

Show your code, or show you the door. There are so many native Mac and iOS apps out there right now perfectly capable of rendering Markdown and streaming text. You just gotta wonder what is this guy’s excuse.

iamcalledrob - 5 hours ago

Fun fact: This is how Apple used to do it too.

Old versions of macOS / AppKit used to use WebKit to render rich text inside their native NSTextFields. Turns out text is hard :)

And besides, the native WebView is super fast and lightweight, and its not unreasonable to use it as a text layout engine. You could use separate webviews for every row in a table and you'd still get fantastic performance.

iMessage for mac used to use a webview too. Adium as well. HTML is absolutely the right tool for the job if you're rendering rich/marked-up text.

danielvaughn - 8 hours ago

I remember being a junior engineer in 2015, and being asked to render a clickable link within a paragraph in an iOS app. Swift had just been released so we were still entirely on the ObjC/UIKit stack. It was an absolute nightmare. I _barely_ managed to make it work. I haven't really touched iOS since about 2016, so I assumed the new SwiftUI stuff would have this stuff built in. Obviously. Kind of insane that it wasn't.

skeledrew - 8 hours ago

> how immature all these “native” things still are when you step outside simple screens

Well yeah. If people don't invest sufficient effort in a thing why would there be an expectation for that thing to become mature? People are locked into web tech because that's where the greater majority of the effort has been going. Quite literally people look at native, say it isn't developed enough, and go develop for the web even more. Cycle repeats. Hardly anyone wants to put in the effort to improve native when things already "just work" for the browser.

splittydev - 8 hours ago

I've had pretty much the same experience with my AI chat app. Nothing works well. Markdown rendering is slow and laggy, streaming is slow and laggy, everything locks up the UI. I've tried at least 5 of the most popular text editor components for UIKit and SwiftUI on GitHub, and all were broken in one way or another, buggy, and slow as well. It's ridiculous.

rubymamis - 8 hours ago

Yep, this is a difficult problem. I wrote extensively how I managed to solve this by creating my block editor from scratch using Qt C++ and QML[1]. I faced similar issues - selection between discrete blocks, showing the underlying Markdown under the cursor, varying delegate sizes, etc.

I'm using what I learned to create a native LLM client with a streaming Markdown parser[2].

[1] https://rubymamistvalove.com/block-editor

[2] https://www.get-vox.com

sirwhinesalot - 8 hours ago

If you need to display HTML content (what Markdown usually translates to) then WKWebView is the control to use! Or use something like litehtml which should be more than enough for Markdown unless you want to support "Animated Gifs" (that are actually H.264 movies these days) or whatever else.

You can still use native controls for the rest of the UI and have 0 Javascript running. I'm not sure I understand what the problem with NSTextView was though. It's pretty performant as far as I can tell?

ryandrake - 8 hours ago

I don’t recall ever struggling with NSTextView. I never really got into Swift, but I’ve never found Cocoa / Objective C to have any of the problems the author mentioned.

Not exactly sure what “streaming” text is, but serial terminal software has been handling incremental text rendering and updating for decades, without performance struggles.

PaulHoule - 9 hours ago

Yep. Electron is the worst way to make a desktop app… except for all the others!

c-smile - 2 hours ago

> There is no real alternative.

Not sure if my Sciter qualifies as a native solution.

Check this chat alike virtual list with MD items: https://sciter.com/wp-content/uploads/2026/05/virtual-list-m...

Yes, MD gets translated to DOM tree. But virtual list implementation in Sciter is a native thing. Load whole chat is not an option usually. Yes, JS is used in process but mostly as a configuration option: take output of one native function -> transform it -> pass as an input to other native function.

Essentially there is no so significant difference with any other SwiftUI/TextKit solution. It is just a difference in terms - SwiftUI uses tree of Views that is conceptually the same as DOM tree in terms of Sciter.

freequest - 2 hours ago

I’ve been there too. Finally opted for Flutter (need cross-platform mobile and desktop). Apple needs to put a big effort into the development tools, or they will face the actual Windows situation: several GUI toolkits, none of them as mature as the ones they are designed to replace. (Try to beat Windows Forms Professional Control Libraries and the boost in development performance you get. You can’t because the tool makers need a clear path and commitment in order to justify developing a new version of the full control libraries. You need cross-platform; forget the native tools. That’s the same scenario Apple is facing right now.)

arjie - 4 hours ago

A thing I’ve always wanted was a visual JSON viewer that instantly opened on multi-hundred-meg files. So I used Claude Code to build one with native text views and it’s true it’s pretty raw. But for a thing that doesn’t need formatting, dictionary, and all that it’s great. The viewer opens fast enough that it’s dominated by the window rendering animation which is about what I wanted here.

So I think the text view is pretty low level so that it can support this.

cyber_kinetist - 9 hours ago

I just wish there was a native Markdown renderer / editor library in C that I can use cross-platform - in the style of something like IMGUI (where the library outputs a list of primitives for you to render yourself in any graphics API).

Or well... since we now have Claude I might have a jab at this someday in my free time.

pier25 - 7 hours ago

Maybe controversial but I think HTML + CSS is truly the most powerful system to make GUIs.

There’s really nothing else out there that competes with a similar performance and productivity.

This old article by the Missive team (the email client) convinced me.

https://medium.com/missive-app/our-dirty-little-secret-cross...

lokimedes - 3 hours ago

We did https://markant.md with TextKit 1, flies through multi-megabytes markdown files with latex rendering etc. took some scaffolding (like only rendering attachments when they are close to the viewport) to make it smooth, but it wasn’t really a big problem.

tedggh - 6 hours ago

One of the reasons I decided to stay in the shadows as an unglamorous, boring backend developer. Every single time I tried any frontend development, either web or mobile, the moment I started running into issues like this requiring witchcraft to accomplish an objectively trivial task, a bit of my soul left my body.

wwalexander - 32 minutes ago

Just use AttributedString

- 6 hours ago
[deleted]
teddyh - 7 hours ago

I know nothing about any of these APIs, but the claim of the article seems weird. If naitive APIs are insufficient, or slow, or unsuitable, and implementing your own is too hard, then how does Electron even do what it does? One would assume that Electron has its own library to accomplish the task, in which case this code could either be separated, or re-created once and for all, into its own re-usable library.

krzyzanowskim - 7 hours ago

"skills issue" but also "native" frameworks are lacking polished API. On macOS TextKit2 is unfortunately kinda broken, how do I know? I reimplemented TextView with it https://blog.krzyzanowskim.com/2025/08/14/textkit-2-the-prom...

Yokohiii - 7 hours ago

I am currently experimenting with linux based GUIs. It was always something that felt clunky to me, but now with more insights, it's clunky for a reason. If you need more then a framebuffer, then rendering something sophisticated to the screen is insanely complex. Somehow it's easy to expect that rendering text on a screen should be easy, but when you go down the layers you find yourself with a club and a flint stone trying to build a castle with it.

Wayland is another product of this hardships, going wayland native seems only feasible when all stars align around it. But then you are stuck in that place.

That being said, without deeper knowledge about SwiftUI, I find it a bit odd to expect so much from a novel concept. Native desktop dev is already kind of niche, considering the dominance of web dev. Chrome (and it's artifacts) is probably the best funded software in the world and google's incentive to improve it is above all. It's not a miracle that it just works. It's effort and tons of cash.

d12bb - 8 hours ago

Why not use native for UI frame (menu, toolbar, conversation list etc) and WebKit for the actual chat? I think that would combine the best of both worlds.

zhxiaoliang - 7 hours ago

I understand your pain. That’s why I’ve ported my VMPrint layout engine to Rust. It’s early, but it already shows promising performance improvements over the original TypeScript-based engine, which is already very fast. The Rust version can create fully paginated, publishing-grade layout at around 8,500 pages (or 2,000,000 words) per second on a M4 MacBook. It’s even faster at advanced tasks like mixing texts with irregular exclusion fields. The TS version can do it under 1ms, but I don’t have a measure yet for the Rust version. Unfortunately, people have shown little interest in this kind of components, so I’m no longer inspired to release it in its raw form like I did with VMPrint. My plan is to use it to build a native markdown editor first to test it more fully and just to have fun with it, LOL.

StilesCrisis - 7 hours ago

Everyone loves to complain about the "bloat" in Chrome, but how many have actually taken the time to measure it against a native rewrite? Love this article. We take so much for granted in the modern WebKit/Blink stack. Modern multilingual text processing is a genuinely hard problem.

elch - 9 hours ago

How is "performance" defined? Does it take into account the amount of memory required in each case?

chromadon - 8 hours ago

This is where QT/JUCE can help. Although you are limited to c++.

ozgrakkurt - 7 hours ago

The problem here is that you are not choosing based on knowing how the render pipeline is implemented in these tools and how it would work with your usage of it.

You can do a couple days to a week of reading to understand the fundamentals once and then you will actually know what you are doing.

It is not proper to choose things on “battle tested” or other meaningless words

pjmlp - 8 hours ago

I was using Markdown text editors with WPF back in 2012....

And yes WPF is a framework native to the Windows platform ecosystem.

lewisjoe - 7 hours ago

If you squint enough, you'll see the official Google doc app for Android/iOS is a webview (i.e the editor part)

Fancy text rendering/editing is hard to implement when you leave the luxury of webviews.

waynecochran - 8 hours ago

This explains why so many AI chat tools suck at text selection on MacOS / iOS. They got the streaming and markdown part right … flicker free, but at the cost of text selection.

delduca - 7 hours ago

How bear solves this? It is looks native to me.

inatreecrown2 - 8 hours ago

Not just text. Try to build a ui where you need non-trivial and non-standard behavior and SwiftUI will fail. AppKit is still better in this regard.

titzer - 7 hours ago

Electron runs like crap on older hardware. It's sad that native UI frameworks never got their shit together, but I think if you want performant text rendering you just gotta reduce your expectations. If you're fine with less fancy fonts and "scripting" your UI in something else than JS, then native can work. But it very quickly reveal that you should avoid everything that uses JSON. JSON is just a disease vector for the JavaScript world to infect everything else.

usernametaken29 - 8 hours ago

Kotlin MP is also pretty decent on Mac

saagarjha - 8 hours ago

You can just embed a web view in your app, though?

dzonga - 6 hours ago

markdown to html. or markdown stays markdown.

the browser never chokes on html.

tantalor - 7 hours ago

No insight as to why this is happening?

Where is the profile? Where is the bottleneck?

Just complaining with nothing to contribute.

BoredPositron - 8 hours ago

Hu? We just switched from textual to native because native markdown rendering is finally good. If it was written a year or two ago ok... but now is odd.

dist-epoch - 8 hours ago

the only place where native UI is still better is for ultra-complex UIs - image/video/3d/audio editors. and only because it's easier to create custom UI widgets/renderers than on web stack.

that's it, for everything else native UIs are complete garbage compared to HTML/CSS/reactive frameworks.

vasco - 8 hours ago

I once tried mobile development in semi early days android. At the time I made a free Hackaday reader app because I was a daily reader and loved it.

I remember spending 4 hours to make a scrollable element that wasn't jumpy or buggy. There were several stackoverflow answers full of gotchas explaining all you had to do. I finished and published the app but never again. Native stuff has terrible developer experience.

diego_moita - 8 hours ago

Outside of niche applications (e.g. virtual desktops, gamming, embedded systems) native UIs are dead.

There are even parts of both Windows and MacOS rendered through HTML. If I remember correctly, at least in Windows 10, File Explorer was rendered through Internet Explorer.

Web rendering doesn't need to be only through Electron/Node. There are other libraries much more performant and lean (Dioxus, etc).

distantsounds - 8 hours ago

do you miss Hypercard yet?

BillStrong - 7 hours ago

I think the article misses the actual point?

The browser is faster because they went native, in particular, GPU.

Every issue described is text rendering related. Everyone.

And I would bet most of the SwiftUI issues could be solved with a text render cache.

Something like Casey Murati's refterm toy that showed what that can do with no other optimizations, or the work for GPU accelerated terminal emulators like alacritty or ghostty.

reddysuyesh - 8 hours ago

[dead]

tanlethanh - 4 hours ago

[dead]

- 7 hours ago
[deleted]
RyanJohn - 8 hours ago

[dead]

camgunz - 8 hours ago

I thought models were so good we could vibecode a text renderer for $50. What's the problem here? /s