Solid
Register the root component
import ResourcesWebGPU from '@uno.build/ui/ResourcesWebGPU'
import UI from '@uno.build/ui/UI'
import { registerRootComponent } from '@uno.build/ui/solid'
import App from './App.jsx'
const canvas = document.querySelector('canvas')
const resources = await ResourcesWebGPU.create({ canvas })
const { ui } = await UI.create({ resources })
// Solid
const solid = registerRootComponent(App, { ui })
solid.mount({})Solid updates call ui.update() automatically after reactive changes settle. Keep the viewport setup and render loop from First Layout to draw the UI with ui.draw().
Use one registered root per UI and call solid.mount(props) once to mount it. Drive subsequent updates with signals; another mount() call creates a new root instead of updating the existing root's props.
Call solid.unmount() to remove the component tree and run its cleanup before destroying the UI. It does not destroy the UI or dispose shared resources; see Destroy.
Configure the compiler
The uno integration uses Solid 2. With Vite, pass compilerConfig to the Solid plugin:
// vite.config.js
import { defineConfig } from 'vite'
import solid from '@solidjs/vite-plugin'
import { compilerConfig } from '@uno.build/ui/solid/config'
export default defineConfig({
plugins: [solid(compilerConfig)],
resolve: {
alias: {
'uno-ui/solid': '@uno.build/ui/solid',
},
},
})compilerConfig sets generate: 'universal' so JSX creates uno nodes. It generates imports from uno-ui/solid, which the alias above resolves to @uno.build/ui/solid.
The demo below compiles JSX directly in the browser with Babel Standalone and @dom-expressions/babel-plugin-jsx, using compilerConfig.solid.
Components
@uno.build/ui/solid exports five components: View, Text, Image, ScrollView, and Input. They render uno nodes and share the properties and event props below. Each component's section describes its additional props and behavior.
<View>
View is a container for layout, backgrounds, and child components. Rendering a View creates an uno node, equivalent to calling ui.create() in the imperative API. Solid adds the node to its parent and manages its updates and removal. Use Solid signals to update its styles in response to events. Read each signal by calling its getter inside JSX.
// SolidView.jsx
import { createSignal } from 'solid-js'
import { View } from '@uno.build/ui/solid'
export default function App() {
const [isHovered, setHovered] = createSignal(false)
return (
<View
style={{
width: '100%',
height: '100%',
alignItems: 'center',
justifyContent: 'center',
}}
>
<View
onPointerOver={() => setHovered(true)}
onPointerOut={() => setHovered(false)}
style={{
width: '200px',
height: '150px',
backgroundColor: '#4377bb',
opacity: isHovered() ? '0.5' : '1',
}}
/>
</View>
)
}<Text>
Use Text for all text content. Follow Texts & Fonts to load and register a font before rendering the examples below.
import { View, Text } from '@uno.build/ui/solid'
export default function App() {
return (
<View style={{ padding: '16px', gap: '8px' }}>
<Text style={{ color: '#ffffff' }}>Hello from Solid.</Text>
</View>
)
}A string directly inside View, such as <View>Hello</View>, is invalid. Text is a leaf node: it accepts strings, numbers, reactive expressions, and fragments containing only text, but cannot contain uno nodes. To use different styles within a line, place sibling Text components inside a View with flexDirection: 'row'.
<Image>
Image displays a registered image resource. It does not download the image from src. Follow Images to load and register the asset before calling solid.mount({}).
| Property | Value | Default | Usage |
|---|---|---|---|
src | String | Required | The registered image resource identifier. |
width | String | Not set | Width with units, such as '128px'. If only this dimension is set, the registered aspect ratio is preserved. |
height | String | Not set | Height with units, such as '100px'. If only this dimension is set, the registered aspect ratio is preserved. |
style.objectFit | 'fill', 'contain', 'cover', or 'none' | 'fill' | Controls how the image fits within the component's dimensions. Set it inside style. |
With neither dimension set, the component uses the registered image size. Dimensions in style take precedence over the width and height props.
Use the same identifier as the component's src:
import { Image, View } from '@uno.build/ui/solid'
export default function App() {
return (
<View style={{ flexDirection: 'row', gap: '16px' }}>
<Image src="assets/coin.png" width="128px" />
<Image src="assets/coin.png" width="160px" height="100px" style={{ objectFit: 'contain' }} />
</View>
)
}<ScrollView>
ScrollView clips its children and provides vertical scrolling by default.
| Property | Value | Default | Usage |
|---|---|---|---|
horizontal | Boolean | false | Arranges the content in a row and enables horizontal scrolling when true. |
Give it a limited height so that content can overflow the viewport:
import { For } from 'solid-js'
import { ScrollView, Text, View } from '@uno.build/ui/solid'
const ITEMS = Array.from({ length: 20 }, (_, index) => index + 1)
export default function App() {
return (
<ScrollView style={{ width: '240px', height: '200px' }}>
<For each={ITEMS}>
{(item) => (
<View style={{ padding: '12px', flexShrink: '0', backgroundColor: '#4377bb' }}>
<Text style={{ color: '#ffffff' }}>Item {item}</Text>
</View>
)}
</For>
</ScrollView>
)
}Set horizontal to arrange the content in a row and enable horizontal scrolling:
<ScrollView horizontal style={{ width: '240px', height: '80px' }}>
<For each={ITEMS}>
{(item) => (
<View style={{ width: '120px', padding: '12px', flexShrink: '0' }}>
<Text style={{ color: '#ffffff' }}>Item {item}</Text>
</View>
)}
</For>
</ScrollView>The style prop applies to the viewport. Use the onScroll event to respond to scrolling.
<Input>
Input is a visual component controlled by value. It displays text, a placeholder, and a blinking caret while focused.
| Property | Value | Default | Usage |
|---|---|---|---|
value | String, number, or null | undefined | The displayed input value. An empty string, null, or undefined is treated as empty. |
placeholder | String, number, or null | undefined | Text displayed only when value is empty and the input is unfocused. |
placeholderTextColor | Color string | '#777777' | The color used for the placeholder text. |
Pass the displayed text through value:
import { Input } from '@uno.build/ui/solid'
export default function App(props) {
return (
<Input
value={props.value ?? ''}
placeholder="Your name"
style={{ width: '240px', height: '40px', padding: '8px', color: '#111827' }}
/>
)
}Input does not create a DOM input or handle IME, selection, or clipboard input. To support typing in a browser, connect a native <input> outside the uno component tree, synchronize its value with a Solid signal, and manage its focus through onFocus and onBlur. See the demo below for a complete example.
Event props
All five components accept the following event props. Pass a handler function to subscribe; omit the prop or set it to null or undefined to remove your handler. Solid manages the listener registration and cleanup.
| Prop | uno event | When it fires |
|---|---|---|
onPointerDown | pointerdown | A pointer is pressed on a node. |
onPointerMove | pointermove | A pointer moves over the UI or during an active pointer interaction. |
onPointerUp | pointerup | An active pointer is released. |
onPointerCancel | pointercancel | The platform cancels an active pointer interaction. |
onPointerOver | pointerover | A node becomes the pointer's hover target. |
onPointerOut | pointerout | A node stops being the pointer's hover target. |
onClick | click | A node is activated by a completed click or tap. |
onWheel | wheel | Wheel or trackpad input occurs over a node. |
onScroll | scroll | A scroll container's offset changes through scrolling. |
onFocus | focus | A node gains uno focus. |
onBlur | blur | A node loses uno focus. |
Handlers receive uno events rather than DOM events. Each event includes these common members:
| Member | Meaning |
|---|---|
type | The uno event name, such as 'pointerdown'. |
target | The uno node where the event originated. |
current_target | The uno node whose handler is currently running. |
source_event | The original platform event, or null for a programmatic event without a source. |
stopPropagation() | Stops the event from continuing to ancestor nodes. |
Events bubble through the uno node tree, so a component's handler can receive events from its descendants. Event-specific data, such as pointer coordinates, wheel deltas, scroll offsets, and focus transitions, is documented in Events.
Refs and handles
In Solid, refs on View, Text, and Image receive the uno node directly: use node.layout or node.focus(), without nodes.main. ScrollView and Input instead expose compound handles. Import ScrollViewHandle and InputHandle from @uno.build/ui/solid when using TypeScript.
| Component | Ref value | Available members |
|---|---|---|
View, Text, Image | uno node | Node properties and methods directly |
ScrollView | ScrollViewHandle | nodes.main (viewport), nodes.content (scrollable content) |
Input | InputHandle | nodes.main, nodes.content, nodes.text, nodes.caret, focus(), blur() |
nodes.caret is null when the input is unfocused. focus() and blur() change uno focus; they do not open a platform keyboard or provide text input.
useUI()
useUI() returns the UI passed to registerRootComponent. Call it during component initialization inside that registered component tree. For example, a component can read the original dimensions of the registered assets/coin.png image:
import { Text, useUI } from '@uno.build/ui/solid'
export function ImageSize() {
const ui = useUI()
const { width, height } = ui.resources.getImageSize('assets/coin.png')
return (
<Text style={{ color: '#ffffff' }}>
Image size: {width} × {height}
</Text>
)
}