How to use ChakraUI on native mobile

Magne Gåsland
7 min readApr 4, 2021

— Update 2021–05–03 (one month later)

Chakra UI has just announced they will be coming to Native “pretty soon”!

https://twitter.com/chakra_ui/status/1388033321213612032?s=21

— (original blog post below)

This post grew out of the discussion on the React Native issue for Chakra UI, plus my own research. I fear some of the brief points @steida made on the issue were lost to some, as they were to me, so I decided to write a bit more thoroughly on them.

First, a primer on React Native Web (RNW), for those unfamiliar. RNW is taking the high-level API of React Native, onto the Web. “Why not just use React?”, you say. RNW is all about using specifically tailored _native cross-platform components_ (that primarily render onto a native Screen view) and also rendering them on the web (to the DOM). Which is possible because RN/RNW uses higher-level abstractions (`<View>` and `<Text>` instead of `<div>` and `<span>`, etc.). (RNW should have been called “React Platform”, really.)

You can’t use Chakra UI with React Native or React Native Web, since they already have styling baked in.

Like @steida said, React Native Web (RNW) has its own fully integrated styling solution, StyleSheet, which has its own API.
The StyleSheet solution comes from RN, naturally. But on web, with RNW, it needs some justification. Why not simply use any other stylesheet solution? In short: To have a uniform styling API across RN and RNW. But there are other benefits too, like working with a higher-level abstraction:

React Native Web abstracts away the complexities of CSS. CSS allows 3 ways of styling, which make it complex (unless you “own the whole stack”, like RN and RNW):
* statically (css file; cacheable and fast)
* dynamic runtime styling (props object or inline styles; flexible)
* escape hatch styling (hooking into DOM nodes outside of React; typically used for animations).

“The React-DOM ecosystem doesn’t have a foundation upon which everything else is built. So, in RN if you install a RN package, then (pretty much) everything is using the same style library, using the same measurements etc. so it can interop at this quite broad level.” — Nicolas Gallagher, RNW creator, at 29:00 in this 2018 podcast

The StyleSheet solution that RN/RNW has is one of the fastest CSS-in-JS solutions, apparently, according to Evan Bacon, Expo Web creator.

So React Native has its own fully integrated props based styling API. Thus, integrating Chakra UI with RN/RNW wouldn’t be particularly desirable, because you’d lose that high level API which they are all about. That’s also why you don’t want to use an extra CSS-in-JS library like styled-components or emotionjs on top of RNW, like @steida expressed. (I don’t think people still attempt to do that because they dislike the RNW solution, or prefer string interpolation instead of RNW’s StyleSheet. They are just confused, like I was, and think they need a styling solution with RN/RNW, when in reality it is already baked in.)

So you can’t use Chakra UI out of the box with React Native.

Neither would you want to do it in RNW, because of RNW’s high level API. RNW is not meant for using a component library made for web, such as Chakra UI, on native. To do that, while also getting the cross-platform benefits of RNW, then Chakra UI would have to be rewritten from the bottom-up with those higher-level abstractions in mind (`<View>` instead of `<div>` etc., and with StyleSheet instead of styled-system and emotion under the hood). This is not likely to happen. The issue has not had much progress since Oct 2019, and was closed in Apr 2020.

It’s probably better to use Chakra UI where it shines: on the web. _Many websites and webapps don’t need to be native_, after all. Going for RN or RNW for them would be pure overhead (even though Expo Web has done great things to reduce that overhead..).

Unless you want to circumvent the React Native Web API

In the TypeScript implementation, I’m extracting most of the component logic into hooks so it can be consumed in React Native Web and React (Web). Perhaps, it might help. — segundeadebayo, Chakra UI creator

But, as said, integrating Chakra UI with RNW wouldn’t be particularly desirable, because you’d lose that high level API which RNW is all about. So it defeats the point of using RNW at all.

And unless you want to make a mobile app that exposes a WebView and loads in a webpage with ChakraUI on it.

Though you could use RN to make a native wrapper/shell app that exposes a WebView in which you load your webapp that uses Chakra UI, of course.

But then you would have to write your own bridge to communicate between your native app and your webapp (at least until Basecamp open sources their bridge for that, Hotwire Strada, later this year). You might be able to write the native app in React Native, and communicate with the webapp through the WebView, but this is hacky, and I’d rather rely on a proper bridge of some sorts.

NB: This type of bridge is not the same as RN’s own bridge which is between the RN app and the native platform.

Capacitor, as an alternative to RN, is the only solution I know of that will easily give you a _single direct bridge_ between your webapp and the native platform (think ‘Electron for mobile’). Read more on Capacitor at the end of this post.

Magnus UI vs. Dripsy — Chakra UI alternatives for RN/RNW

If you want to use RN/RNW and want to use a component library like Chakra UI, then you have two good alternatives, to my knowledge. Especially if you want to use NextJS to do Server-Side Rendering (SSR) of the webapp/PWA. Here is a brief comparison of **Magnus UI vs Dripsy**:

Both are themed, both are inspired by Chakra UI and Theme UI, and on web they both support SSR via something like NextJS.

Magnus UI:

* Utility first
* Component library: _”Magnus UI comes with a set of polished React Native components that just works out of the box.”_ magnus-ui.com
* Not yet responsive, but planned responsive with react-native-media-queries, which makes pure CSS media queries also run on native (with device orientation). Since Magnus UI generates pure CSS media queries when run on web. They consider it more performant than using Fresnel. But the jury is out… Alternatively, it might be that Magnus UI will use react-native-extended-stylesheet as a drop-in replacement for the StyleSheet in React Native which also supports media queries on native.

Dripsy:

* Started in Jun 2020 likely since Magnus UI didn’t support responsivity through CSS media query breakpoints. ref
* Primarily a design system. Relies on you combining it with other React Native component libraries. nandorojo/dripsy#why
* Uses the Dimensions API on Android & iOS.
* Uses actual CSS breakpoints on web, to become responsive, even when using SSR. Uses Fresnel to achieve this. CSS breakpoints on web will rely on the mobile device’s user agent for most cases. But since this can be inaccurate, it also uses pre-emptive server-side breakpoint generation. Basically, _if_ the mobile user-agent cannot be _accurately_ detected, Fresnel renders _all_ media query breakpoints on the server (a bit of extra work for the server, since it might lead to rendering more components). So the client’s browser will receive all breakpoints on first render and can immediately start rendering according to the correct ones. Instead of waiting for React to rehydrate before only then running the media queries with CSS-in-JS, which would have given latency and potentially unwanted visual side-effects. This becomes most acute when you are using SSR, and thus don’t want to wait for rehydration on the client to start showing the responsively laid out content.
* Dripsy is very declarative: it allows you to provide object and array values to add mobile-first responsive styles. Instead of manually using the Dimension API (on native), and adding media queries and nested styles throughout your code (on web). This API is very inspired by Chakra UI’s array syntax for declaring responsiveness. (Which Magnus UI also is inspired by).

So if you want to use RN/RNW then either of these seems the way to go, instead of using Chakra UI.

But if you are determined to use Chakra UI on mobile, and are willing to sacrifice using RN/RNW, there is an option.

Capacitor — To get Chakra UI in a mobile app, with a big caveat

Instead of using React Native (RN), a different option to get to use Chakra UI on mobile (and other platforms) would be to use Capacitor, which is a native runtime/bridge for webapps (think ‘Electron for mobile’).

Capacitor supports iOS, Android and PWAs. There are also a community plugin that deploys Capacitor to Electron, opening up Capacitor apps to MacOS, Linux, Windows etc.

Because Capacitor provides a native runtime environment for web apps, that means it can be used to turn any React web app into a native app. So apps using Material-UI or Chakra or Prime or Ant or Ionic Framework, or any other React UI library, can be turned into native apps using Capacitor (see our examples repo for real code in a variety of libraries).

This simply isn’t possible with React Native. Most popular React UI libraries target the web and react-dom, and most web libraries use web technologies like CSS that aren’t supported in React Native (at least not in their native format)

https://capacitorjs.com/blog/native-react-apps-without-react-native

NB: Using Capacitor in practise means bundling your website inside the app, NOT loading it on demand (via a url). That is the recommended option from Capacitor’s creator Max Lynch, since if not: _”Apple will likely reject your app since it is not “self-contained.”_. To make it self-contained, you can do a NextJS static export, for example. Sadly, for distribution, this means going through the App Store process, and asking clients to update their app for every code change (many will thus be out of date). Unless you use a service such as CodePush for Capacitor. Never mind the weirdness of using a code distribution tool for native apps, just to _serve_ users with fresh HTML, CSS and JS…

The End.

Correct me if I’m wrong in any of this. This is at least what my research has turned up. Hope it helps someone.

Feel free to share alternative solutions or general approaches in the comments.

--

--

Magne Gåsland

MSc. in Computer Science, independent consultant, and curious philosopher.