Styling

OneJS supports inline styles, USS (Unity Style Sheets), CSS Modules, and Tailwind (built-in, no external dependencies).

Inline Styles

Apply styles directly to elements:

<View
    style={{
        width: 200,
        height: 100,
        backgroundColor: "#1a1a1a",
        padding: 20,
        borderRadius: 8,
    }}
>
    <Label text="Styled content" style={{ color: "#ffffff" }} />
</View>

Value Types

Numbers: Interpreted as pixels:

style={{ width: 100, padding: 20 }}

Strings: For percentages, keywords, or complex values:

style={{ width: "50%", height: "auto" }}

Colors: Hex, rgb, rgba, or named colors:

style={{
    backgroundColor: "#ff0000",
    color: "rgb(255, 255, 255)",
    borderColor: "rgba(0, 0, 0, 0.5)",
}}

Layout Properties

Dimensions

style={{
    width: 200,
    height: 100,
    minWidth: 50,
    maxWidth: 400,
    minHeight: 50,
    maxHeight: 300,
}}

Flexbox

style={{
    flexDirection: "row",      // "row" | "column" | "row-reverse" | "column-reverse"
    flexWrap: "wrap",          // "nowrap" | "wrap" | "wrap-reverse"
    justifyContent: "center",  // "flex-start" | "center" | "flex-end" | "space-between" | "space-around"
    alignItems: "center",      // "flex-start" | "center" | "flex-end" | "stretch"
    alignContent: "center",
    flexGrow: 1,
    flexShrink: 0,
    flexBasis: "auto",
}}

Spacing

style={{
    // Shorthand (applies to all sides)
    margin: 10,
    padding: 20,

    // Or individual sides
    marginTop: 10,
    marginRight: 10,
    marginBottom: 10,
    marginLeft: 10,
    paddingTop: 20,
    paddingRight: 20,
    paddingBottom: 20,
    paddingLeft: 20,
}}

Shorthands like margin, padding, borderWidth, borderColor, and borderRadius are automatically expanded to individual properties.

Positioning

style={{
    position: "absolute",  // "relative" | "absolute"
    top: 10,
    right: 10,
    bottom: 10,
    left: 10,
}}

Visual Properties

Backgrounds

style={{
    backgroundColor: "#2a2a2a",
    backgroundImage: texture,  // Texture2D or RenderTexture
}}

Background images accept Unity Texture2D, RenderTexture, or GPU compute RenderTextures:

import { loadImage } from "onejs-unity/assets"

function Card() {
    const [texture, setTexture] = useState(null)

    useEffect(() => {
        const tex = loadImage("images/card-bg.png")
        setTexture(tex)
    }, [])

    return (
        <View style={{ backgroundImage: texture, width: 200, height: 150 }}>
            <Label text="Card Content" />
        </View>
    )
}

Borders

style={{
    borderWidth: 1,
    borderColor: "#333333",
    borderRadius: 8,
    // Or individual sides
    borderTopWidth: 2,
    borderLeftColor: "#ff0000",
    borderTopLeftRadius: 4,
}}

Display

style={{
    display: "flex",     // "flex" | "none"
    visibility: "visible", // "visible" | "hidden"
    overflow: "hidden",  // "visible" | "hidden"
    opacity: 0.8,
}}

Typography

<Label
    text="Styled text"
    style={{
        fontSize: 16,
        fontStyle: "bold",        // "normal" | "bold" | "italic" | "bold-and-italic"
        color: "#ffffff",
        unityTextAlign: "middle-center", // Text alignment
        whiteSpace: "normal",     // "normal" | "nowrap"
    }}
/>

USS Stylesheets

For reusable styles, use USS files:

/* styles/main.uss */
.card {
    background-color: #2a2a2a;
    padding: 20px;
    border-radius: 8px;
    margin-bottom: 10px;
}

.card-title {
    font-size: 18px;
    color: #ffffff;
    margin-bottom: 10px;
}

.button-primary {
    background-color: #0066cc;
    color: #ffffff;
    padding: 10px 20px;
    border-radius: 4px;
}

.button-primary:hover {
    background-color: #0077ee;
}

Load and apply the stylesheet:

// Load at startup
loadStyleSheet("styles/main.uss")

// Use classes
<View className="card">
    <Label text="Card Title" className="card-title" />
    <Button text="Action" className="button-primary" />
</View>

Note: For standalone builds, USS files loaded via loadStyleSheet() need to be copied to StreamingAssets. Alternatively, use CSS Modules or Tailwind which embed styles in the JS bundle automatically.

StyleSheet API

OneJS provides functions for loading and managing stylesheets at runtime.

loadStyleSheet

Load a USS file from the working directory:

loadStyleSheet("styles/main.uss")  // Returns true if successful

compileStyleSheet

Compile a USS string and apply it to the root element. If a stylesheet with the same name already exists, it will be replaced automatically (deduplication):

const uss = `
.my-class {
    background-color: #333;
    padding: 10px;
}
`
compileStyleSheet(uss, "my-styles")  // Name used for deduplication

This is how CSS Modules and Tailwind work internally - they embed USS in the JavaScript bundle and call compileStyleSheet() at runtime.

removeStyleSheet

Remove a specific stylesheet by name:

removeStyleSheet("my-styles")  // Returns true if found and removed

clearStyleSheets

Remove all JS-loaded stylesheets. Does not affect Unity asset-based stylesheets:

const count = clearStyleSheets()  // Returns number of stylesheets removed
console.log(`Removed ${count} stylesheets`)

Hot Reload Behavior

Stylesheets are automatically deduplicated by name. When you hot reload your app, re-importing CSS Modules or Tailwind won't accumulate duplicate styles - the existing stylesheet is replaced.

Pseudo-classes

USS supports pseudo-classes for interactive states:

.button:hover {
    background-color: #333333;
}

.button:active {
    background-color: #444444;
}

.button:focus {
    border-color: #0066cc;
}

.input:focus {
    border-color: #0066cc;
    border-width: 2px;
}

Combining Styles

Use both className and inline styles:

<View
    className="card"
    style={{ width: 300 }}  // Inline overrides USS
>
    <Label text="Content" />
</View>

Inline styles take precedence over USS classes.

Dynamic Styles

Compute styles based on state:

function Button({ active, children }) {
    return (
        <View
            style={{
                backgroundColor: active ? "#0066cc" : "#333333",
                padding: 10,
                borderRadius: 4,
            }}
        >
            {children}
        </View>
    )
}

Style Objects

Extract and reuse style objects:

const styles = {
    container: {
        padding: 20,
        backgroundColor: "#1a1a1a",
    },
    title: {
        fontSize: 24,
        color: "#ffffff",
        marginBottom: 20,
    },
    button: {
        padding: 10,
        backgroundColor: "#0066cc",
        borderRadius: 4,
    },
}

function Screen() {
    return (
        <View style={styles.container}>
            <Label text="Title" style={styles.title} />
            <Button text="Click" style={styles.button} />
        </View>
    )
}

Common Patterns

Centering

// Center children
<View style={{
    justifyContent: "center",
    alignItems: "center",
    height: "100%",
}}>
    <Label text="Centered" />
</View>

Full Screen

<View style={{
    position: "absolute",
    top: 0,
    right: 0,
    bottom: 0,
    left: 0,
}}>
    {/* Content fills screen */}
</View>

Responsive Width

<View style={{
    width: "100%",
    maxWidth: 800,
    marginLeft: "auto",
    marginRight: "auto",
}}>
    {/* Centered, max 800px */}
</View>

Debugging Styles

When USS selectors aren't applying as expected, use the built-in debugging utilities to inspect the visual tree.

Dump Visual Tree

Use __dumpUI() to output the element hierarchy with USS classes:

// Dump entire UI from root
console.log(__dumpUI())

// Dump specific element with depth limit
console.log(__dumpUI(myElement, 5))

// Include computed styles
console.log(__dumpUI(myElement, 5, true))

Output shows element types, names, and USS classes:

<VisualElement name="root" class="unity-ui-document">
  <VisualElement class="container">
    <Button class="unity-button btn-primary">
    </Button>
  </VisualElement>
</VisualElement>

Find Elements by Class

Use __findByClass() to locate elements with a specific USS class:

// 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:

// 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.