# OneJS Documentation > Build cross-platform apps and games with React 19, powered by Unity's GPU-accelerated rendering. Source: https://v3.onejs.com/docs --- # Introduction OneJS lets you build UIs with React and TypeScript that render through Unity's GPU-accelerated graphics pipeline. Write familiar web code, deploy everywhere Unity runs. ## Two Worlds, One Runtime OneJS bridges **web development** and **game engines**: - Use **React 19**, hooks, JSX, and the npm ecosystem - Render through **Unity's UI Toolkit** - GPU-accelerated, not a webview - Access **any C# API** directly from JavaScript - Deploy to **desktop, mobile, web, consoles, and VR/AR** from one codebase ## For App Developers If you're building cross-platform applications, your current options have painful tradeoffs: | Solution | Problem | |----------|---------| | Electron | Ships Chromium (~150MB), high RAM usage, CPU-bound rendering | | Tauri/WebView | Still browser rendering under the hood | | Flutter | Different language (Dart), different ecosystem | | React Native | Mobile-focused, limited desktop support | **OneJS offers something different:** - **True GPU rendering** - UI Toolkit renders on the GPU, not a browser engine - **No webview overhead** - No DOM, no layout engine, no Chromium - **React you already know** - Hooks, components, JSX, TypeScript - **Unity's capabilities** - Mix 2D UI with 3D scenes, use shaders, physics, audio - **Smaller builds** - No bundled browser engine ## For Game Developers Game UI development has been stuck in the past - verbose C# code, slow iteration, limited modding support. OneJS brings modern practices to game UI: - **Declarative components** - Write UI as React components, not imperative C# code - **Hot reload** - See changes instantly without recompiling - **Separation of concerns** - UI logic in JavaScript, game logic in C# - **First-class modding** - Players can modify UI without touching game code - **Web dev accessibility** - Expand your team with JavaScript developers ## Platform Support From a single React codebase: | Platform | Notes | |----------|-------| | Windows, macOS, Linux | Desktop builds | | iOS, Android | Mobile builds | | WebGL | Browser builds (uses V8/SpiderMonkey with JIT) | | PlayStation, Xbox, Switch | Console builds | | VR/AR | XR device builds | ## How It Works ``` React Components → onejs-react Reconciler → UI Toolkit Elements → GPU Rendering ``` When you write: ```tsx ``` ### Find Elements by Class Use `__findByClass()` to locate elements with a specific USS class: ```tsx // Find all elements with class "btn-primary" console.log(__findByClass("btn-primary")) ``` Returns element info including pseudo-states and computed styles: ``` Found 2 elements with class 'btn-primary': Type: Button Name: submit-btn Classes: [unity-button, btn-primary] Pseudo States: [:hover] Styles: backgroundColor: rgba(0.24, 0.47, 0.99, 1.00) ``` ### Find Elements by Type Use `__findByType()` to find all elements of a specific type: ```tsx // Find all TextField elements console.log(__findByType("TextField")) // Find all Buttons console.log(__findByType("Button")) ``` ### Common Debugging Scenarios **Selector not matching**: Dump the element to see its actual USS classes and verify your selector matches. **Style not applying**: Check if a higher-specificity rule is overriding yours. Inline styles always win. **Pseudo-class issues**: Use `__findByClass()` to see which pseudo-states (`:hover`, `:focus`, etc.) are active. **Inherited styles**: Remember that UI Toolkit uses visual tree inheritance, not DOM inheritance. Dump the parent chain to trace style sources. --- # Events Handle user interactions with React-style event props. ## Click Events ```tsx ) } ``` ## How It Works The plugin transforms `.module.uss` files at build time: 1. Generates a unique hash from the file path 2. Appends the hash to all class names: `.container` becomes `.container__a1b2c3` 3. Exports a mapping object: `{ container: "container__a1b2c3" }` 4. Calls `compileStyleSheet()` to inject the CSS at runtime Your component uses the scoped class names, avoiding conflicts with other styles. ## Dynamic Classes Use bracket notation for dynamic class selection: ```tsx import styles from "./Button.module.uss" type Variant = "primary" | "secondary" | "ghost" function Button({ variant = "primary", children }) { const className = `${styles.container} ${styles[variant]}` return } ``` ## TypeScript Support With `generateTypes: true`, the plugin creates `.d.ts` files automatically: ```typescript // Button.module.uss.d.ts (auto-generated) declare const styles: { readonly "container": string readonly "primary": string readonly "secondary": string readonly "ghost": string } export default styles ``` This gives you full autocomplete and type checking for class names. ## Combining Classes Multiple classes work as expected: ```tsx {children} ``` Combine with conditional classes: ```tsx {children} ``` ## Pseudo-classes USS pseudo-classes work normally: ```css /* Input.module.uss */ .input { border-width: 1px; border-color: #333; } .input:hover { border-color: #666; } .input:focus { border-color: #0066cc; border-width: 2px; } ``` The plugin correctly scopes the base class while preserving pseudo-class selectors. ## USS Variables Custom properties work in `.module.uss` files: ```css /* Theme.module.uss */ .container { --accent: #e94560; --text: #ffffff; padding: 20px; } .title { color: var(--accent); } .body { color: var(--text); } ``` See [USS Variables](/docs/core-concepts/styling#uss-variables) for full details. ## Global Styles For global styles that shouldn't be scoped, use regular `.uss` files: ```css /* global.uss - not scoped */ .unity-button { /* Targets Unity's built-in button class */ } ``` Load global styles with `compileStyleSheet()` directly. ## File Structure Recommended organization: ``` components/ ├── Button.tsx ├── Button.module.uss ├── Card.tsx ├── Card.module.uss └── Input.tsx └── Input.module.uss ``` ## Full Example ```css /* Card.module.uss */ .card { background-color: #1a1a1a; border-radius: 8px; padding: 20px; } .header { flex-direction: row; justify-content: space-between; margin-bottom: 16px; } .title { font-size: 18px; color: #ffffff; } .content { color: #999999; } ``` ```tsx import { View, Label } from "onejs-react" import styles from "./Card.module.uss" function Card({ title, children }) { return ( {children} ) } ``` ## Hot Reload CSS Modules work seamlessly with hot reload. Stylesheets are automatically deduplicated by name - when you modify a `.module.uss` file and the app reloads, the existing stylesheet is replaced rather than duplicated. This happens because each CSS Module uses its file path as the stylesheet name when calling `compileStyleSheet()`. The runtime tracks stylesheets by name and removes any existing stylesheet before adding the updated one. ## Manual Cleanup If you need to programmatically manage stylesheets: ```tsx // Remove a specific CSS Module's styles removeStyleSheet("components/Button.module.uss") // Remove all JS-loaded stylesheets clearStyleSheets() ``` See [StyleSheet API](/docs/core-concepts/styling#stylesheet-api) for more details. --- # Tailwind CSS OneJS includes a built-in Tailwind-like utility class generator. No external dependencies required - just import and use. **Related:** [Styling Basics](/docs/core-concepts/styling) | [CSS Modules](/docs/guides/css-modules) ## Setup Tailwind is enabled by default in the esbuild config. Just add the import to your code: ```tsx import "onejs:tailwind" ``` That's it! The plugin scans your source files for class names and generates USS automatically. ## Basic Usage Use Tailwind classes directly: ```tsx import { render, View, Label, Button } from "onejs-react" import "onejs:tailwind" function App() { return (