A 2025 Survey of Rust GUI Libraries
56 points by legoktm
56 points by legoktm
This reads like a rough experience. By the author’s count, less than about 10% of the libraries met the threshold for development and functionality purposes.
This would be interesting to read from the perspective of other languages and toolkits. Windows certainly isn’t the best development platform for many languages but this kind of experience and experimentation is valuable.
I didn’t make it all the way through the author’s list but in general this matches my experience in the fall of 2024 quite well. I had a greenfield project that needed a UI and before committing to doing it in C++ I decided to have a look at Rust and see if this might be a good first project… answer: no. There were a ton of early-stage UI libraries and none of them seemed particularly fit for purpose. Many of them had very slick websites and looked like they had potential but digging into the actual API docs and seeing what was there and not there was disappointing.
So I went back to Qt and C++ and was quite happy with the outcome. I didn’t get the benefit of the borrow checker and friends, but Valgrind was happy with the code and I didn’t really have any memory-safety-related bugs.
Oh, I’m certain the experience is dreadful with Rust. I’m not focused on that.
I was curious about other toolkits and other languages. Qt used from C++ makes for a pretty good standard in general. I would be curious to know about other alternatives, be it languages, toolkits, or both. This is a curiosity mostly to assess the landscape for language bindings.
For knocking out quick prototypes I’m a fan of Dear Imgui. It’s imperfect in a lot of ways for many applications but it hits me right in the dopamine. I’ve got a template that’s based on the mainline example code that I use and I can go from an empty directory to doing stuff and plotting the results (ImPlot) in under an hour. Very satisfying!
I would love to have something similar that interfaces well with Python and is also simple enough that I’m not constantly referring to the documentation (PyQt…). I haven’t found it yet.
Are you familiar with Kivy? I’m not experienced with it but it seems that the project trying to be on par with Flutter.
I feel like any sufficiently deep/mature widget library will require working side-by-side with documentation unless you are using the exact same widgets in the exact same way across multiple applications. As long as there is adequate documentation available or a sizable enough community so you can look at the code from others, I generally don’t see it as a point of friction. Add in good IDE support and that should allow for pretty good productivity. Qt also has Qt Creator for rapid prototyping and design. I know some other toolkits are trying to offer similar tools. Kivy had a UI Designer but I think it’s become unsupported.
I looked at it a while ago and just scrolled through the Getting Started guide and some of the other documentation. Kivy looks like it would be great to build and maintain an application in. Lots of similar vibes as Qt, which I also don’t mind for building and maintaining things in.
This isn’t a criticism, more of a philosophical difference: the majority of the code that I work on that needs a UI doesn’t need a long-term maintainable UI. Kivy, like Qt, looks very much like choosing to use it means you’re building a Kivy Application. Most of what I’m working on is challenging computational problems (lots of computational geometry and complex linear algebra) where I want to be able to quickly put some kind of quick interface on it to visualize the output and potentially adjust the input (or just edit the input in an external editor and hit the “Run” button in the app to redo the processing with the new input).
I’d just use something like Jupyter but it’s pretty limiting as far as 3D and dynamic visualization goes. Dear ImGui hits the sweet spot for me because there’s virtually no ceremony to it. I plop some simple commands into main(), instantiate the processing library in a separate thread with an input queue, and use ImGui widgets to send events to the library thread and plot the output with ImPlot. Often the UI portion ends up being less than a screenful of code.
I don’t need two-way property bindings or a complex event management system. I don’t need “separation of concerns” and an entirely different language to learn to manage the widgets. If I need to do some composition I’ll use a couple of functions that wrap a group of widgets into a reusable thing I can call.
And not that this is a Kivy thing but I’d also really rather not worry about bringing a browser into it and writing JavaScript and then have to figure out ways to safely serialize data and plot it (whether it’s a regular browser or something like Electron).
Edit: not to make a long reply longer but I almost love Flutter. Dart is a cool language. The “just return a data structure and get a UI” thing is really great. The place where I ran into issues was that the “cross-platform” stuff was highly unpredictable for which subset of platforms it would actually work on. The project I used it for was a phone/tablet app that used the camera. Worked great on iOS and Android. Camera functionality was half functional on OS X and not at all functional on Linux. It was weird in a browser. Ended up writing some Objective C code on OS X and C++ code on Linux and worked through the bindings I needed, but it definitely went from “this is cross-platform and easy” to “you need to learn a bunch of minutia about Dart FFI and platform-specific stuff” in a hurry.
After an experience with many frameworks, I’ve also settled on Dear Imgui for anything which doesn’t need to look like consumer facing software. It works, performance is solid and it’s extremely small in size. I’ve yet to find anything that remotely comes close.
egui in this list is an equivalent of sorts but native to rust, and so it’s unsurpising it does well. imgui fails though their accessability which again is unsuprising since it is targeted at the games/graphics industry which is not very accessible for obvious reasons.
The specific task in this link is an interesting one because it is decidedly non-trivial when doing from scratch…. but it is totally trivial when using the OS-provided controls.
My minigui.d library passes the test on Windows very easily, because when you do new TextLabel
it does CreateWindow("static")
and new LineEdit
is CreateWindow("edit")
so directly using the system controls with minimal wrapping.
…then I went to recreate that on Linux. Qt isn’t especially usable from D, and GTK isn’t usable period, so I did my own custom thing. Finally got the text edit working pretty ok…. like 20,000 lines later (note that I did basically all of it myself, there are some middle grounds available too). And even there, the IMEs work, but screen readers do not (it is on my list, but it is kinda daunting just to look it). So I still recommend people use the Windows version for those use cases. I’m just now looking at the Mac, got my custom versions almost working there with a little porting effort, but again, the good experience will be using the native views there too, and that’s a fair chunk of work.
So I get the desire to say “forget it” and just only do the custom thing. It feels more portable when you get started. It kinda is more customizable - a lot of times, the native things do offer a lot of customization but the apis are broad and it can take tons of work to do basic things (for example, changing the border color of something might mean going to an owner drawn paradigm… which means you are responsible for a lot more than just the border color).
But frankly, I think using the native platform options is worth it. You gain more than you lose. Even beyond narrator and input method integration, there’s just so so so many little interactions that people expect that are easy to overlook when DIYing, but just work when you use the native options.
On the other hand, if your custom text area actually works with all this, it presumably means you unlocked all the necessary integration apis - which means it is available (hopefully) to the user of your library too. So when they make radically different custom controls, they can also throw in some aria-role
or whatever bits to piggy back on that integration too. Which is likely to be needed at some point; the OS native controls do a lot, but not everything.
I always say “graphics” is a small minority of a graphical user interface - the user interface parts are a much bigger job.
but screen readers do not (it is on my list, but it is kinda daunting just to look it)
I can understand why. I’m the original developer of AccessKit, the Rust library project that all of the Rust DIY GUIs with any screen reader accessibility are currently using. AccessKit has a C API, so you can use it directly if you want. Or if you prefer, you can look at the code and maybe translate some of it for your library; it’s MIT/Apache dual-licensed, so should be compatible with your use of the Boost license. Hope this helps.
Yes, indeed, I’ve been (loosely) following that project as something to use as a guide too. One of the things the readme says though is on point:
We realize that most developers who might use AccessKit are not experts in accessibility. So this project will need to include comprehensive documentation, including a conceptual overview for developers that are learning about accessibility for the first time.
I’ve barely even actually used the aria-* tags in html, so I think some newb tutorials would be pretty useful, spelling out stuff that might be obvious to many but obscure to a bunch of us lucky devs like how end users actually interact with it. I’ve fired up Windows Narrator and a couple other screen readers before, but 15 minutes of use is gonna be different than someone who actually knows it well. Contrast an experienced vim user with the poor user hitting the cliche wall of :w!
, same idea here.
So the basics still help a lot, the and seeing the implementations are a good starting point, just it still feels I have a lot to learn before being actually able to make it all work, even with your project as a (very!) helpful guide.
I did GUI stuff years ago and there was always something painful which made new libraries attractive. On top of that, I enjoy writing OCaml and new libraries with OCaml bindings were very attractive. This was with the GTK+2 years where lablgtk offered a really friendly and effective API but it couldn’t hide some of the terrible choices with GTK+2 (the list and tree widgets were something, and probably still are, unless maybe if they’ve been deleted and there is no replacement of course).
There were so many libraries already but I settled on one simple criteria: does it support accessibility? It’s multi-faceted but in practice, as you explained, this amounts to not re-inventing everything, and not using funny renderers which is probably cushy’s issue (it seems to use wgpu and I guess it renders everything in a single opengl surface). Or having deep pockets and a lot of time, which applied to the incumbents (qt, gtk, blink/webkit, win32, …).
The main reason I settled for that is that if you use something which doesn’t support accessibility and its audience increases, then you will need it. And it will be painful. Either you’ll have to add the support in the library, or migrate your UI, which may require changing its architecture. You’re basically setting yourself for a world of pain.
edit: actually, another criteria: what does the tree/list API look like? Sure, these are not the widgets used the most but same, when you need them, you don’t want to end up crying.
During my survey I found GPUI to be the best. Well designed lib and one of the few that is used in production for a non-toy app. I am on macOS, have a web background and Zed UI is a strict superset of the things I am planning to build. Author is coming from a totally different perspective with probably more Windows, C++, Qt etc background.
Here is a smaller open source app built with it: https://github.com/MatthiasGrandl/Loungy
I agree with the conclusion: Slint is the more polished, traditional GUI for Rust. But it has two potential downsides: licensing, which you need to be aware it’s LGPL and you need to use it as a shared library in case you don’t want to affect the license of your program, and that it’s very DSL heavy. This allows Slint to escape some Rust limitations that impact how to do stateful widgets while being ergonomic but some people may dislike it as it even ships with a small imperative language inside the DSL.
Otherwise egui it’s an interesting choice, maybe easier for simple GUIs. I was left with a bitter taste with this test of qmetaobject, as it’s one of the best Qt bindings for Rust. But I understand that setting up all of that in Windows is not easy.
This is inaccurate. Slint can be statically linked without the LGPL affecting you, because you can use its proprietary free license instead as long as you’re not doing embedded, which permits essentially doing anything an open source project would need (you can redistribute app+lib like it’s open source, but not the lib alone without an app).
Slint’s biggest leg up was also not mentioned in the article: it has a live preview with drag-and-drop editing (I think it is the only library in the list with any kind of preview). This is more or less impossible without it being a DSL, which is why I don’t consider that a downside.
They also ship and LSP and code formatter tool (and recently started shipping a tree-sitter grammar) making it easier to add support for .slint files to one’s editor of choice.
The main pain point I had with Slint is how to use with a tokio run-time. I think that is mostly a Rust skill issue on my side though.
I believe live previews are a feature supported by Qt Creator as well. If the author were able to get any of the Qt-based options in the article to work, that could have been available.
LGPL allows static linking just fine. You need to ship your binaries in a way that allows re-linking by a user, but there’s no requirement that that linking be dynamic
I know I’m super late, but re: han unification, I’d reckon that when you use a Japanese IME, it uses a Japanese font, since the differences between the selection of rendering hanja/hanzi/kanji is done via font selection. I encounter this frequently when I message friends hanzi and they get kanji, because of font selection.
Not only can Narrator not see this text [GTK 4]
AccessKit support has just been merged recently inro GTK, so accessibility on Windows and macOS (and Android soon??) should work in the… next release (?)
Leptos is a Web frontend framework that is for some reason on the Are We GUI Yet? list. The README has an FAQ about native GUIs that says it’d be possible to build native GUIs with Leptos but it’s not actually supported because it sent the whole codebase into generics hell when they tried it.
I get this from a pure-native perspective, but after a fling with lib-ui bindings (i wanted an embeded webview >u<), I’ve accepted webview front-ends as a neccessary evil. With a tauri-leptos-trunk
stack I can build a responsive cross-platform frontend for Desktop, Mobile, and Web, shipped as an AppImage, APK, or WASM bundle, with a native SIMD or WASM-SIMD backend where applicable. The same cargo-workspace could have firmware crates that interoperate with the frontend over native or web-usb, full-stack rust.
Prior works include RustyTube (where I found trunk), and any of a handful of tauri-leptos demos (including an impl. of the Medium-esque realworld.io
demo spec). I had to adapt such examples for Tauri v2 and Cargo workspaces, and iterated on the whole bundle as I learned more about each piece, about other projects and community conventions, and imposed my own (minimalist, know-your-stack) preferences.
I could make an updated template (w/o workspaces) – there was a gap to clear – but most of the work was learning Tauri, and how it meshes with my prefs. I didn’t hit any major roadblocks by starting with a Tauri v2 template and following the aforementioned leads. I think it’s a pleasant stack (webviews come with eg. web accessibility), and there’s enough examples/docs for someone driven to put the pieces together. Cargo itself is a blessing and a curse: tests will be ergonomic, but I’m sticking to Trunk CSR (no tauri-leptos SSR feature-flag) because of feature/cfg-hell, and I hear from the RMK folks that they’re waiting for per-package-target
to stabilize (for, uh, that use-case). Beyond GUI’s, shoutout to Kanata for it’s seriously impressive cross-platform Desktop input stack.
my dream job is contributing to an ecosystem of interoperable cross-platform apps for the public good. ig i should join the us digi corps before i age out of it, but tbh i don’t want anything to do with the fed rn, or seemingly any company large enough to hire juniors… some days i worry i’ll never have the chance to pursue that vision on such a grand, structured, or collaborative scale. other days i think i’m working towards it, that my efforts and proselytization will snowball, chance, or amount into something that matters. other days i believe i’ll pass in a bike lane having failed to sell myself, to have meaningfully and sustainably applied my skillset, whether out of an economic reality or a failure to advocate for myself. today’s been mixed. it helps to have been able to do little goods, for friends, locals, apps for non-tech employers, individuals and niche communities. i wish i could support myself doing it, dedicate myself, work with more than an inactive upstream and another solo-weekend fork, on something bigger, without crushing work/life or failing to support myself.
a bit off script, 2025 got me daydreaming that i’m anywhere else >u<