Tamagui 1.0 – Cross-platform React apps in less time, with better performance
tamagui.dev
tamagui.dev
I built the first library for React Native that supported Web/responsive design (Dripsy), so it's cool for me to see Tamagui taking this idea to the extreme.
Those seem mostly non-reusable?
Tamagui basically solves the part of styling + rendering UI. It works on both web and native.
As for logic/data fetching...this has gotten far, far better in React over the past few years.
For data fetching, assuming you're using REST, @tanstack/react-query is incredible. It gives you a "hook" to wrap any async function, and returns loading states, errors, etc.
In the past, people used Redux, but it's out of fashion now. I prefer a library called zustand whenever I need non-data related global state management.
= Ridiculously high percentage of code re-use across web and react-native apps.
What a time to be alive!
We also get a lot of very positive feedback on our modern Redux Toolkit package, which we designed to simplify Redux usage [1], and it includes our "RTK Query" data fetching and caching API as well [2], which is similar to React Query in use case and API.
[0] https://blog.isquaredsoftware.com/2022/07/npm-package-market...
[1] https://redux.js.org/tutorials/essentials/part-2-app-structu...
Probably the mentioned hooks-based approaches are indeed fashionable now. Remains to be seen whether they’ll stick around.
We make an app that contacts lots of microservices in sequence and combines the data in many ways. Having automatic refetching, caching and the like by default makes a world of difference.
This is not fashion. It’s quality.
I don't know if it's still the case but when I started my career (granted, some decades ago) using the new hotness X/Motif + C++, there were still more lines of COBOL around than anything else. (Hell, might not have been the case then, but that was the yarn.)
The official «Tamagui + Solito + Next + Expo Monorepo» starter:
https://github.com/tamagui/tamagui/tree/master/starters/next...
Or the more recent version that builds on that and adds tRPC and authentication (with Clerk):
create-universal-app - https://github.com/chen-rn/CUA
Of course a person can get used to these things, but I question whether it scales to non-tiny teams. There’s a real smell of ye olde dynamic class creation here which React moved away from for very good reasons
If you’re talking about the styled() helper, that is something many React style libraries have standardized on from Emotion to Styled Components to Stitches. And actually it’s very important for an optimizing compiler because it limits you down to a statically analyzable subset that focuses just on styles. There’s no magic there either - React Native itself has a similar API with StyleSheet.create, except it won’t optimize even with a future compiler when you start nesting multiple things. That’s where styled() shines.
The exact same conversations were had when JSX came along, react-native-web, etc. We just keep on piling up more and more abstractions.
Some replies: you don’t have to use a special stack you can pass in any component. Theme values and media props are definitely a bit of sugar but hardly magic - they map 1 to 1 to CSS and the other most popular style libraries. And writing them any other way (cross platform) simply doesn’t exist or is much much more complex, so I see them as both necessary and incredibly easy to understand coming from CSS.
The styled function is the whole point! That’s the whole library so that can’t really go away, and it’s just a plain old function there’s 0 magic there.
useMediaPropsActive is a utility function exported for very advanced use cases and it says as much in the docs.
I’ll give you variants, those are borrowed from Stitches and other libraries. They solve several problems elegantly and are also easy to understand. If there’s only one new thing to learn with something as complex as a style library, I’ll take that. Especially with how nice variants are.
No disagreeing that it can be a nice experience using a system like this where things "just work" if you stay within their boundaries; but there is no denying the sheer complexity of it. It is absolutely magic vs say, a bit of HTML + CSS - in which case you can consider what's going on inside the browser as magic.
In my experience, it rivals other web-only libraries, especially with the compiler.
This is still such a problem - as a small startup we still have two completely separate code bases that we need to maintain with a tiny team (though we share Redux and Tailwind thanks to https://www.npmjs.com/package/twrnc). If we could "flutterize" our apps and make them run everywhere like this lib allows us to that'd save a huge amount of time.
Wrote an essay about our current solution here: https://nikodunk.com/2022-05-10-the-tech-stack-for-maximum-e...
We need to launch a mobile app because someone started impersonating our web app and abusing our API. Their Google Play app has 100k+ installs, and it's rapidly growing. They're giving us a bad name too by injecting ads and degrading performance.
We have a React/TypeScript app (in a monorepo if that matters) and need to launch something on Android to get rid of these copycats.
Not us: https://play.google.com/store/apps/details?id=com.headbreyz....
(NB: I'd love to contract or hire someone to do this, in case anyone on HN is interested.)
React seems less than 2x slower than painfully optimized vanilla code in js-framework-benchmark, even considering the "swap rows" test, which is not that important but where React does terribly in. https://krausest.github.io/js-framework-benchmark/current.ht...
Basically it’s hard to be fully precise, but if anything 2x rounds down in the big picture.
Tamagui is a style and component library (plus optimizing compiler). Do you know of any standard benchmarks for any of those?
I feel this sort of approach lacks honesty and fails to be objective. Anyone can cherry-pick a customized test where their stuff comes out as the best of class, no matter how underperforming it is.
To have a proper apples-to-apples comparison, standard benchmarks are the way to go. Everything else sounds like snake oil and hand-waving.
>> Basically it’s hard to be fully precise, (...)
> Not really. Just put together a benchmark and let it speak for itself.
You seem a little bit split on this one :) Yes, creating a fair benchmark is hard. Yes, it's hard to get other people to evaluate their things using your benchmark. Yes, it's hard to do an apples-to-apples comparison.
Not really. By "putting up a benchmark" I mean an objective and verifiable standard set of performance tests that everyone interested can contribute their best effort.
I means nothing if you roll out a cherry-picked ad-hoc test that compares a corner case of your best effort to a half-assed underperforming implementation of a competitor you chose because it suits you best.
There are standard benchmarks out there, which were already mentioned in this discussion. It takes virtually no effort to roll out Tamagui's best effort. Not using those actually requires more effort than using them, which casts doubt over the validity of self-serving cherry-picked ad-hoc tests.
The other benchmark posted tests more framework level stuff, but could be repurposed to show a more “typical app screen” with some effort.
Tamagui is a style and component library (plus optimizing compiler). Do you know of any standard benchmarks for any of those?
In the ideal you'd have to benchmark a heavy screen that you'd have to write for every competitor, and then provide timings across many different facets - initial load, runtime, total time, window resize, etc. As far as I know no one does that for anything, even backend stuff as it's just too much effort (even the TechEmpower benchmarks are micro and not like this).
If anything though Tamagui will look even better there. I've open sourced the results, re-used benchmarks from rival libraries, shown my work, and even published the 3 benchmarks that don't do as well for Tamagui. It's as Apples-to-Apples as it gets and it's not measuring anything weird this is straightforward stuff.
There actually is for web frameworks https://github.com/krausest/js-framework-benchmark
I’d love to make a benchmark someday despite my bias, maybe just a profile page or feed or something generic, and could have side tests for animations, theme changes, responsive styles, and logical styles. Those are the key areas for a style library. Tamagui is actually 10x or more at a few of them.
Not really. Just put together a benchmark and let it speak for itself.
The benchmarks speak for themselves.
> Button only supports a limited subset of text props directly, and doesn't accept hoverStyle text props. If you need more control, you can do a simple customization using some exported helpers.
> Please note that this pattern is a bit antithetical to the multiple-components APIs that Tamagui generally prefers. In a future release we hope to fix this, but that change should be easy to migrate to.
I don't understand what any of that means, but it sounds like Tamagui doesn't support hover styles on Button components out of the box. That's a huge deal breaker for me. The docs give an example of what they mean by "simple customization", but the code is completely unintelligible to me, and far from simple.
I also haven't seen an example of Tamagui being able to render web and native React components from the same code. So it seems to me that either calling it "cross-platform" is a stretch, or the documentation is just very terrible.
As far as I know there's no alternative for cross-platform styling and SSR.
Love the variants API and responsive styles for native too.
However, one thing notably absent from the page and a quick Google search are layout animations. React-Native has this in the (poorly-supported and almost-niche) form of LayoutAnimation, however support is notably missing in React-Native-Web and other frameworks attempting to bring true cross-platform support.
As for me (not that anyone cares), this is a very cool advancement, but doesn't change many of the complaints against the current (and numerous) set of issues with JS, and will be sticking with Flutter.
92.5 kB Minified
30.1 kB Minified + Gzipped
https://bundlephobia.com/package/@tamagui/core@1.0.1> Works completely at runtime, no compiler necessary.
So is the style part comptime or runtime? Because runtime is definitely undesirable.
Using react-native-web is not as straight forward as it first sounds, as there a lot of packages that don't support web and just crash when trying to run the RN app on web.
Would this solve that problem, to be able to easily move a React Native mobile app to web?
Your best bet is using React Native Web and removing dependency on the packages that don’t support web: remove/treeshake them, shim them (like RNW does with RN), or detect the platform using a conditional and then exclude the troublesome package/component in favor of a web compatible one.
Alternatively: Keep the web app separate from the native one, and simply share logic and some shared components (RNW) in a monorepo. Could be the easiest path forward, but will give some duplication of code.
My two cents, FWIW. Someone who has done the transition themselves, or has more insight to your particular case could probably offer even better advice.
The best way is to go through your package.json dependencies one by one, figure out which support web and which don’t, then go into your project and make an empty component (eg: file.web.js) for any component that doesn’t work on the web. Once you have your app up and running on the web (even with a ton of “blank” web components), start the work of finding web equivalents for the missing functionality. Be diligent that the props for the native component and web component are the same or at least compatible, so that the component calling the now web compatible component needs no changes.
In my experience it’s super important to keep “platform specific” code isolated into its own component. General layout and the skeleton of your app should remain cross platform. In-line use of Platform.OS should be kept to a minimum.
I like your suggestion though, a good start to see how much of a lift RNW would be or if it is just better to start "fresh" through Next.js
RNW was independent of styled components, but you could use them together.
Keen to hear from anyone else who's used both Tamagui and Nativewind as well.
There is significant latency when interacting with the components and animations seem to render at ~10fps.
With some chunk splitting and a good hosting, it has always seemed reasonable to me.
The main argument for me when choosing a front end framework is the availability of ready-made UI components, and React has always been ahead thanks to MUI.
I'm just an amateur/hobbyist at front end development though, curious what real front end developers care about most in a framework. Especially, isn't that a huge pain not to have access to all the wonderful MUI components when leaving react?
On the value of MUI and what senior front end devs care about, you’d find this interesting (esp the linked youtube of Theo): https://twitter.com/magnemg/status/1608634824591544320
Remix.run and RedwoodJS are two fullstack React frameworks that comes from old RoR folks who aim to recreate the Rails/Laravel experience for JS/TS. Remix is SSR and progressive enhancement / web standards focused, and RedwoodJS is CSR and GraphQL focused and brings a larger and more opinionated suite of tools (testing etc.). Coming from Rails myself, RedwoodJS gave me the most Rails-like feel, but YMMV.
NextJS is the market leader for a fullstack React framework, ofc (and Solito.dev that bridges NextJS and Expo works well with Tamagui). But if you want more freedom, and a Vite based setup with ‘blazingly fast’ DX, then try vite-plugin-ssr.com
BlitzJS is «the missing fullstack toolkit for NextJS» also made by a RoR guy trying to make NextJS come closer to the Rails DX we knew and loved.
For data loading in particular, that works crossplatform, with both NextJS and React Native, I recommend:
tRPC, as a favored choice amongst many, to call backend functions directly from the frontend (it uses React Query under the hood to handle caching, retries etc.), and gives the mich loved full stack TypeScript type inference.
If you decide you need GraphQL - like if you need to expose your API to third parties, or have strict frontend/backend team separation - then I recommend:
GQty.dev on the client, for inferred queries/mutations. Rapid dev speed. Move to URQL or Relay at scale.
pothos-graphql.dev on the server, for auto building the schema from your TS code (aka. code-first). Better than Nexus.
That will give you fullstack type inference with GraphQL like with tRPC, and either will give your the fastest dev speed, closest possible to Rails.
That’s the gist of it. Hope it helps!
https://dev.to/redbar0n/the-railslaravel-experience-in-jsts-...
If the post is useful, I’ll improve it based on feedback in the comments there.
I don't see any screenshots, so I presume it's the entire site?
the entire site is also made with Tamagui, so the landing page uses a lot of it, and you can see visuals and code of all the components in the docs.
It’s true that it’s marginally less performant than vanilla React Native (within 10%, looks like 1.9%):
https://tamagui.dev/docs/intro/benchmarks
But that is actually no small feat for a native component library, see f.ex. Nativebase’s longstanding unresolved performance issues:
https://github.com/GeekyAnts/NativeBase/issues/4302
And for that tiny difference on native, you in return get close to 100% code sharing between native and web. As opposed to writing vanilla React Native and then writing it again for vanilla React.
I guess i am just much more interested in making the native side faster. I have never had issues making something in React Native and then having the web side be the slow part.
If you do pseudo styles or responsive styles with RNW your web app will absolutely tank in all metrics, runtime/lighthouse/load/layout. Tamagui fixes all four. That normally prevents code share for anything more than small apps or totally performance insensitive use cases, otherwise Tamagui makes a big difference.
Luckily I’m confident it will be fixed pretty rapidly, judging by the steady release cycles and impressively pace of improvements by the author.
Want to see something else neat? Open the dev-tools and just wave your cursor over the navigation elements and watch the browser spray GET requests to some json files. I guess they made it Cloudflare's problem, but ... I'm glad I didn't try to view this on mobile
Making claims like this is like claiming SpaceX can’t go to space because their lobby isn’t aerodynamic.
Also the prefetching is Next.js standard practice, not only does it have nothing to do with Tamagui but it’s is good for performance.
The homepage gets excellent lighthouse scores despite being an order of magnitude more complex than your average app due to showing off every feature in the library.
I can see we just have different expectations for a website, so I wish you all the best with your project
If you want to dispute the performance claims please do! But don’t spread FUD. You mis-construed prefetching for some sort of accidental performance mis-step when it’s the opposite and improves performance, without seeming to even realize what it is.
"<17kb, 0-dependency. Every React Native API, typed, without bloat on the web."
https://github.com/tamagui/tamagui/tree/master/starters/next...
Every time I try one of those new shiny things it always looks great at first, but then when "hello world" meets the real world you always hit some wall (be it routing, SSR, styling, state management, data fetching, performance, etc), beyond which things can get pretty messy. I've never seen a real UI codebase that actually looks good.
I wish we could finally get there. Maybe WASM will help shake things up a bit.
Expo - Handles app routing of screens Next.js - Handles web routing of screens (SSR Works) React Query - Handles data fetching and hooks (Expo + Next) (Others are using TRPC with clients in Expo and Next) Zustand - Handles gllobal state (Expo + Next) Tamagui - Component libary (Expo + Next)
Performance on the web with SSR rendering, React-Query pre-caching, and Next.js static builds is insanely good.
You have to bring your data fetching, and state, but `create-tamagui-app` is pretty amazing if you get stuck into it for a couple of hours.
I imagine in a few months there will be a monorepo starter with:
Expo Next Prisma / Supabase auth and database Data fetching with TRPC Tamagui Design System Zustand client-state
Someone's probably working on it right now
Edit: Glad I'm not a web developer.. good luck dudes, haha.
I'm running iOS 16.2 (20C65) FWIW
“ Application error: a client-side exception has occurred (see the browser console for more information).”
The problem with porting gui libs to Linux is - what is "Linux GUI"? Likely you would want to port it to either Qt or GTK; other routes might be a bigger lift.
Fwiw, React Native for Windows targets WinUI & for macOS targets UIKit (though Microsoft's work here builds a lot on Facebook's work targeting iOS).
ahem, CLI. anything else is just bumpers in the bowling alley gutters and training wheels on your bike. (I only partially jest)
I do think it's just a incentive issue. Supporting a platform on React Native takes plenty of effort, so without a big app as both the motivation and test-bed figuring this out there's little reason to invest in it.
[1]: Not really a reference, but just a thread with people's thoughts on this whole mess: https://www.reddit.com/r/csharp/comments/vc3e2l/winui_3_or_w...
1) there's typically just one canonically recommended for a given use case at a given time
2) they tend to a better job interoperating with one another & conforming to a consistent desktop paradigm than popular Linux equivalents (see e.g. running qt apps under gnome)
This is all largely because they come from singular entities - achieving the above would require more effort & coordination from Linux folk (though KDE do a decent attempt - Gnome has a lot to answer for here).