AsheeUI was built with AI.

How it was built is not documented here yet.

Signal: signalAshee Softworks

Installation: Expo

Add the native package to an Expo project and render the same components on a device and in a browser.

installationMarkdown

The components are a separate implementation from the web ones and the same components to write: the names, the props and the colour roles are shared, and the platform decides how each one renders.

@asheeui/native lives in the AsheeUI repository and is not on npm yet, so an application takes it from there. Everything after that step works the way the web installations do.

The apps/expo-playground package in the repository is this page, built: it renders every component in every state, runs on a device and exports to the web.


Before you start

RequirementVersionWhy
ExpoSDK 57The version the native package is built against
React Native0.86.3The version SDK 57 pairs with
NativeWind4.2The classes a native component states
Tailwind CSS3.4NativeWind 4 compiles the v3 directives
Node.js18 or newerThe CLI and the bundler

A version the package was not built against is the first thing to check when a component renders without its styles.


Create a project

If you're starting fresh, scaffold an Expo app:

pnpm create next-app my-app

If you have an existing Expo project, skip to the next step.


Get the packages

The native package is not published, so it is taken from the repository. The packages inside the repository depend on each other with workspace:*, which resolves inside the workspace a package belongs to, so an application joins the workspace rather than installing a copy of it.

package.json

json
{
"dependencies": {
"@asheeui/native": "workspace:*",
"@asheeui/shared": "workspace:*"
}
}

Clone the repository, add your application as a package in it, and install from the workspace root. Nothing is copied into your project in the process: the package ships its source, and the bundler compiles it.


Set up NativeWind

Install the styling layer:

pnpm add nativewind@4.2.7 react-native-css-interop@0.2.7

Then point the bundler, Babel and Tailwind at each other.

metro.config.js

jsx
const { getDefaultConfig } = require("expo/metro-config");
const { withNativeWind } = require("nativewind/metro");
const config = getDefaultConfig(__dirname);
module.exports = withNativeWind(config, { input: "./global.css" });

babel.config.js

jsx
module.exports = (api) => {
api.cache(true);
return {
presets: [
["babel-preset-expo", { jsxImportSource: "nativewind" }],
"nativewind/babel",
],
};
};

tailwind.config.js

jsx
module.exports = {
content: ["./index.js", "./src/**/*.{ts,tsx}"],
presets: [require("nativewind/preset")],
theme: {
extend: {
colors: {
background: "#FFFFFF",
foreground: "#111827",
primary: "#EA580C",
secondary: "#F1F5F9",
danger: "#DC2626",
warning: "#D97706",
success: "#16A34A",
},
},
},
};

global.css

css
@tailwind base;
@tailwind components;
@tailwind utilities;

The application imports that file once, at its entry point:

index.js

jsx
import { registerRootComponent } from "expo";
import App from "./src/App";
import "./global.css";
registerRootComponent(App);

A component gains a className from NativeWind, so the platform's types are declared once:

nativewind-env.d.ts

ts
/// <reference types="nativewind/types" />

Those seven values under colors are the theme's roles rather than a palette invented for one screen: a component states bg-primary and text-foreground, and what those resolve to is the line above. Change them, and the device, the simulator and the browser change together, which is the whole of writing the theme once.


Wrap your application

The provider is mounted once, above everything the application renders, and it holds the defaults a component resolves against:

src/App.tsx

tsx
import { AsheeNativeProvider } from "@asheeui/native";
export default function App() {
return (
<AsheeNativeProvider config={{ defaultRadius: "lg" }}>
<Screen />
</AsheeNativeProvider>
);
}

Verify it works

Render a few components:

tsx
import { Badge, Button, Card, Text, VStack } from "@asheeui/native";
export function Screen() {
return (
<VStack gap="lg">
<Text role="heading-lg">Hello AsheeUI</Text>
<Card title="Inbox" description="12 unread">
<VStack gap="sm">
<Badge color="primary">New</Badge>
<Button onPress={() => {}}>Open</Button>
</VStack>
</Card>
</VStack>
);
}

You should see the heading in the theme's typography, a surface with a border and a radius, and a control in the accent colour. If the components render without their styles, the Tailwind content paths and the Metro plugin are the first two places to look.

To run the same application in a browser, set the web bundler in the Expo configuration and export it:

app.json

json
{
"expo": {
"web": {
"bundler": "metro",
"output": "single"
}
}
}
bash
npx expo export --platform web

Where native differs from web

The vocabulary is shared, and a few things are stated the way the platform states them rather than the way a browser does. They are worth knowing before reading the component reference, which documents the web surface.

  • A disabled control is isDisabled. A native Button states the disabled state as isDisabled, where the web Button states disabled. Both are the same option, spelled the way each platform spells it.
  • Direction is a prop, not a breakpoint class. <Stack direction="row"> lays its children out in a row on every screen. A screen that changes direction at a width asks useBreakpoint and passes the answer, because the platform reports the window as a value rather than as a set of class prefixes.
  • A class is NativeWind's, not Tailwind's. A className on a platform view is a string of classes that the renderer understands or ignores. It is not Tailwind in a browser, so a rule that depends on the cascade behaves differently, and a component's own props are the part that is guaranteed.
  • The package is not published. The web package is on npm; the native one is taken from the repository, as above, and will be published when its remaining components match the web contracts.

Next steps

  • Getting Started: the CLI, the provider and a first component on the web.
  • Components: the component reference, whose vocabulary the native package shares, with the differences listed above.
  • Theming: what each colour role means and how one theme is declared once for every platform.
  • The Expo playground: this page as a working application, including the layout kit. It builds for a device and exports to the web.