> ## Documentation Index
> Fetch the complete documentation index at: https://docs.napps.io/llms.txt
> Use this file to discover all available pages before exploring further.

# React styling

Every JSX node accepts a `style` object. Dimensions and spacing use native density-independent units unless a property explicitly accepts a percentage string.

Styles apply only to the node where you set them. They do not inherit or cascade to descendants.
Set typography, color, spacing, and other values explicitly on each node that needs them. This is
also true for registered `class` styles.

`text` is the inline-text exception for children, not for style inheritance. A `text` node can
contain nested `text` nodes, and each nested text node can contribute its own inline styling. Nodes
such as `box`, `row`, `column`, `img`, or `button` nested inside `text` are ignored as text
children; place them beside the text node in a layout container instead. See the [text node
reference](/js-ui/nodes/text) for an example.

## Property reference

### Colors and backgrounds

| Property             | Accepted value       | Behavior                                                                                                      |
| -------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------- |
| `backgroundColor`    | `string`             | Fills the node background. Use a CSS color string such as `"#2563eb"`, `"rgba(0,0,0,0.5)"`, or a named color. |
| `backgroundGradient` | `string \| Gradient` | Replaces the background color with a CSS-like or structured gradient.                                         |
| `color`              | `string`             | Sets the text or foreground color for providers that support color.                                           |
| `borderColor`        | `string`             | Sets the border color.                                                                                        |

```tsx theme={null}
<box
  style={{
    backgroundColor: "#ffffff",
    borderColor: "#e5e7eb",
    borderWidth: 1
  }}
>
  <text style={{ color: "#111827" }}>Card content</text>
</box>
```

### Shape and borders

| Property                  | Accepted value     | Behavior                                                               |
| ------------------------- | ------------------ | ---------------------------------------------------------------------- |
| `borderRadius`            | `number \| string` | Rounds all corners.                                                    |
| `borderRadiusTopStart`    | `number`           | Rounds the logical top-start corner.                                   |
| `borderRadiusTopEnd`      | `number`           | Rounds the logical top-end corner.                                     |
| `borderRadiusBottomStart` | `number`           | Rounds the logical bottom-start corner.                                |
| `borderRadiusBottomEnd`   | `number`           | Rounds the logical bottom-end corner.                                  |
| `borderWidth`             | `number`           | Sets the border width on all sides.                                    |
| `clip`                    | `boolean`          | Clips child content to the node's bounds, useful with rounded corners. |

Corner names use logical start/end so they work with the app's layout direction.

### Spacing and layout

| Property        | Accepted value | Behavior                                                                                                                                                                           |
| --------------- | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `spacing`       | `number`       | Adds a gap between direct children in a `row`, `column`, `scrollable`, or `pager`. The gap follows the container's layout or scroll direction. It does not arrange `box` children. |
| `padding`       | `number`       | Sets the same inner spacing on every side.                                                                                                                                         |
| `paddingStart`  | `number`       | Sets logical start inner spacing.                                                                                                                                                  |
| `paddingEnd`    | `number`       | Sets logical end inner spacing.                                                                                                                                                    |
| `paddingTop`    | `number`       | Sets top inner spacing.                                                                                                                                                            |
| `paddingBottom` | `number`       | Sets bottom inner spacing.                                                                                                                                                         |
| `margin`        | `number`       | Sets the same outer spacing on every side.                                                                                                                                         |
| `marginStart`   | `number`       | Sets logical start outer spacing.                                                                                                                                                  |
| `marginEnd`     | `number`       | Sets logical end outer spacing.                                                                                                                                                    |
| `marginTop`     | `number`       | Sets top outer spacing.                                                                                                                                                            |
| `marginBottom`  | `number`       | Sets bottom outer spacing.                                                                                                                                                         |

For `scrollable` and `pager`, prefer padding for edge spacing because margin reduces the usable scroll area.

### Size

| Property      | Accepted value     | Behavior                                                                   |
| ------------- | ------------------ | -------------------------------------------------------------------------- |
| `width`       | `number \| string` | Sets the node width. Strings can be percentages such as `"50%"`.           |
| `height`      | `number \| string` | Sets the node height. Strings can be percentages such as `"50%"`.          |
| `minWidth`    | `number`           | Prevents the width from becoming smaller than this value.                  |
| `maxWidth`    | `number`           | Prevents the width from becoming larger than this value.                   |
| `minHeight`   | `number`           | Prevents the height from becoming smaller than this value.                 |
| `maxHeight`   | `number`           | Prevents the height from becoming larger than this value.                  |
| `weight`      | `number`           | Allocates proportional space in a linear parent such as `row` or `column`. |
| `aspectRatio` | `number`           | Maintains width-to-height proportion, for example `1` for a square.        |

```tsx theme={null}
<row style={{ width: "100%", spacing: 12 }}>
  <box style={{ weight: 1, aspectRatio: 1 }} />
  <box style={{ width: 120, height: 80 }} />
</row>
```

### Alignment

| Property              | Accepted value                  | Behavior                                              |
| --------------------- | ------------------------------- | ----------------------------------------------------- |
| `horizontalAlignment` | `"start" \| "center" \| "end"`  | Positions children horizontally within a layout node. |
| `verticalAlignment`   | `"top" \| "center" \| "bottom"` | Positions children vertically within a layout node.   |
| `textAlignment`       | `"start" \| "center" \| "end"`  | Aligns text within its available width.               |

## How layout alignment works

`horizontalAlignment` and `verticalAlignment` are applied by the parent container to its direct
children. They do not change the alignment of descendants deeper in the tree. Set the property on
the `box`, `row`, or `column` that owns the children you want to align.

### Container behavior

| Container | `horizontalAlignment`                                                                          | `verticalAlignment`                                                                              | `spacing`                               |
| --------- | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | --------------------------------------- |
| `box`     | Aligns every child horizontally inside the box. Children remain stacked.                       | Aligns every child vertically inside the box.                                                    | Not used to arrange children.           |
| `row`     | Positions the group of children along the row's horizontal axis when extra width is available. | Aligns each child on the row's vertical cross-axis.                                              | Adds a horizontal gap between children. |
| `column`  | Aligns each child on the column's horizontal cross-axis.                                       | Positions the group of children along the column's vertical axis when extra height is available. | Adds a vertical gap between children.   |

The default alignment is `start` horizontally and `top` vertically. `start` and `end` are logical
directions, so they follow the app's layout direction.

### `box`: align overlaid children

`box` measures its children in the same bounds and uses both alignment properties to place them.
This is useful for badges, overlays, and centered empty states.

```tsx theme={null}
<box
  style={{
    width: "100%",
    height: 180,
    horizontalAlignment: "center",
    verticalAlignment: "bottom",
    padding: 16,
    backgroundColor: "#dbeafe"
  }}
>
  <img
    src="https://cdn.example.com/hero.jpg"
    alt="Seasonal collection"
    resizeMode="cover"
    style={{ width: "100%", height: "100%" }}
  />
  <text style={{ color: "#ffffff", fontWeight: 700 }}>
    Seasonal collection
  </text>
</box>
```

The image and text occupy the same box. The text is centered horizontally and placed at the bottom
of the box. Render order still controls which child is on top.

### `row`: main-axis and cross-axis alignment

For a `row`, horizontal alignment controls the child group along the row. Vertical alignment
controls each child across the row's height.

```tsx theme={null}
<row
  style={{
    width: "100%",
    height: 96,
    horizontalAlignment: "end",
    verticalAlignment: "center",
    spacing: 8,
    padding: 16,
    backgroundColor: "#f2f4f7"
  }}
>
  <text>Subtotal</text>
  <text style={{ fontWeight: 700 }}>€49.00</text>
</row>
```

The children are grouped at the logical end of the available width and centered vertically. The
vertical alignment is visible because the row has more height than its content.

Use a child `weight` to consume remaining horizontal space. Weighted children share that space
proportionally; `weight` has no layout effect on a child inside a `box`.

```tsx theme={null}
<row style={{ width: "100%", spacing: 12 }}>
  <text style={{ weight: 1 }}>Product name</text>
  <button text="Add" onClick={addToCart} />
</row>
```

### `column`: main-axis and cross-axis alignment

For a `column`, vertical alignment controls the child group along the column. Horizontal alignment
controls each child across the column's width.

```tsx theme={null}
<column
  style={{
    width: "100%",
    height: 240,
    horizontalAlignment: "center",
    verticalAlignment: "center",
    spacing: 12,
    padding: 20,
    backgroundColor: "#f9fafb"
  }}
>
  <text style={{ textAlignment: "center", fontWeight: 700 }}>
    Nothing here yet
  </text>
  <button text="Start shopping" onClick={startShopping} />
</column>
```

The child group is centered vertically and each child is centered horizontally. The column needs
extra height for vertical alignment to have visible room to move the group.

Use a child `weight` to consume remaining vertical space:

```tsx theme={null}
<column style={{ height: "100%" }}>
  <text>Header</text>
  <box style={{ weight: 1 }} />
  <button text="Continue" />
</column>
```

### Alignment versus text alignment

These properties act at different levels:

| Property              | Acts on                                      | Example                             |
| --------------------- | -------------------------------------------- | ----------------------------------- |
| `horizontalAlignment` | Direct children of `box`, `row`, or `column` | Center a button inside a column.    |
| `verticalAlignment`   | Direct children of `box`, `row`, or `column` | Center an icon vertically in a row. |
| `textAlignment`       | Text glyphs inside the text node's own width | Center a multiline heading.         |

To center a heading both within its container and within its own width, use the container's
`horizontalAlignment: "center"` and the text node's `textAlignment: "center"`.

### Spacing, padding, and margin

* `spacing` is a parent layout gap. It is horizontal in a `row` and vertical in a `column`.
* `padding` adds space inside the container, so alignment and child layout happen inside the
  remaining content area.
* `margin` adds space outside the node. It changes the node's placement in its parent; it does not
  create a gap between that node's own children.
* On `box`, `spacing` does not arrange overlaid children. Use padding, explicit sizes, or a
  `row`/`column` when you need regular gaps.

Alignment only has extra space to distribute when the container is larger than its content. Give a
container an explicit or weighted size when you need to see centered or end-aligned content.

## Spacing in layout and scrolling nodes

`spacing` is interpreted by the node that owns the children. It is not a universal margin and it
does not add space around the outside edge of a node.

| Node                    | Direction  | Effect of `style.spacing`                                                                                         |
| ----------------------- | ---------- | ----------------------------------------------------------------------------------------------------------------- |
| `row`                   | Horizontal | Gap between adjacent children. `horizontalAlignment` positions the group when the row has extra width.            |
| `column`                | Vertical   | Gap between adjacent children. `verticalAlignment` positions the group when the column has extra height.          |
| `scrollable horizontal` | Horizontal | Gap between direct scroll items. `horizontalAlignment` positions items when content is shorter than the viewport. |
| `scrollable`            | Vertical   | Gap between direct scroll items. `verticalAlignment` positions items when content is shorter than the viewport.   |
| `pager horizontal`      | Horizontal | Gap between pages. This is distance between page bounds, not padding inside a page.                               |
| `pager`                 | Vertical   | Gap between pages. This is distance between page bounds, not padding inside a page.                               |
| `box`                   | None       | Ignored for child arrangement because children are overlaid.                                                      |

### `row` and `column`

Use `spacing` on the parent instead of adding margins to every child:

```tsx theme={null}
<column style={{ spacing: 16 }}>
  <text>Shipping address</text>
  <text>Payment method</text>
  <button text="Continue" />
</column>
```

In a `row` the gap is horizontal. In a `column` it is vertical. `spacing` applies between
children, not before the first or after the last; use padding for those edges.

### `scrollable`

`scrollable` uses `spacing` between direct scroll items. Use padding for the viewport and content
edges:

```tsx theme={null}
<scrollable horizontal style={{ paddingStart: 16, paddingEnd: 16, spacing: 12 }}>
  {products.map((product) => (
    <box key={product.id} style={{ width: 160, height: 220 }}>
      <text>{product.title}</text>
    </box>
  ))}
</scrollable>
```

For a vertical scrollable, omit `horizontal`; the same `spacing` becomes the vertical gap. Do not
use margin on the scrollable for leading or trailing edge space because it reduces the usable scroll
area.

### `pager`

`pager` uses `spacing` as the distance between pages, not as an inner gap within each page. Use
the page's own padding for inner content and the pager's padding for viewport edges:

```tsx theme={null}
<pager
  horizontal
  itemSize="84%"
  snapPosition="center"
  style={{ spacing: 12, paddingStart: 16, paddingEnd: 16 }}
>
  {slides.map((slide) => (
    <box key={slide.id} style={{ padding: 16, borderRadius: 16 }}>
      <text>{slide.title}</text>
    </box>
  ))}
</pager>
```

### Typography

| Property         | Accepted value                             | Behavior                                              |
| ---------------- | ------------------------------------------ | ----------------------------------------------------- |
| `fontSize`       | `number`                                   | Sets text size.                                       |
| `fontWeight`     | `number`                                   | Sets text weight, for example `400`, `600`, or `700`. |
| `fontFamily`     | `string`                                   | Selects a font family available to the native app.    |
| `textDecoration` | `"none" \| "underline" \| "strikethrough"` | Applies text decoration.                              |
| `maxLines`       | `number`                                   | Limits the number of rendered text lines.             |
| `minLines`       | `number`                                   | Reserves at least this many text lines.               |

```tsx theme={null}
<text
  style={{
    fontSize: 18,
    fontWeight: 700,
    textAlignment: "center",
    maxLines: 2
  }}
>
  Limited-time offer
</text>
```

### Transforms and opacity

| Property       | Accepted value | Behavior                                                                                                                                                       |
| -------------- | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `alpha`        | `number`       | Sets opacity from `0` (transparent) to `1` (opaque).                                                                                                           |
| `rotate`       | `number`       | Rotates the node in degrees.                                                                                                                                   |
| `scale`        | `number`       | Sets both horizontal and vertical scale. `1` is the original size.                                                                                             |
| `scaleX`       | `number`       | Sets horizontal scale.                                                                                                                                         |
| `scaleY`       | `number`       | Sets vertical scale.                                                                                                                                           |
| `translationX` | `number`       | Moves the node horizontally in density-independent units.                                                                                                      |
| `translationY` | `number`       | Moves the node vertically in density-independent units.                                                                                                        |
| `transition`   | `string`       | Present in the style type, but not a reliable interaction-animation contract. Use `gestureDetector` with shared values for pressed or gesture-driven feedback. |

Transforms do not change layout measurement; they move or resize the rendered result.

## Gradients

Use helpers from `@napps/nodes`:

```tsx theme={null}
import {
  conicGradient,
  linearGradient,
  radialGradient,
  stop
} from "@napps/nodes";

<box
  style={{
    backgroundGradient: linearGradient(90, ["#111827", "#2563eb"])
  }}
/>;

<box
  style={{
    backgroundGradient: radialGradient([
      stop("#ffffff", 0),
      stop("#dbeafe", 1)
    ])
  }}
/>;
```

Available helpers are `linearGradient`, `radialGradient`, `sweepGradient`, `conicGradient`, and `stop`. Structured gradients accept `type`, `angle`, `centerX`, `centerY`, `center`, `radius`, `colors`, `stops`, and `positions`.

## Named styles

`StyleRegistry` stores reusable styles globally within the runtime:

```tsx theme={null}
StyleRegistry.registerStyle("promo-title", {
  fontSize: 16,
  fontWeight: 700,
  color: "#111827"
});

<text class="promo-title" style={{ color: "#2563eb" }}>
  Featured
</text>;
```

Names are global. Prefix them with the component or extension name to avoid collisions. A class applies only to the node where it is declared; it does not cascade.

## Interaction feedback

Do not rely on `style.transition` for pressed or selected interaction feedback. A gesture has a
native lifecycle, so use `gestureDetector` with a shared value when the visual change needs to be
reliable or animated. Use React state and a normal style update when the selected state does not
need animation.

```tsx theme={null}
const scale = sv(1);

<gestureDetector
  gesture="tap"
  onBegin={() => {
    scale.value = timing(0.96, { duration: 80 });
  }}
  onFinalize={() => {
    scale.value = timing(1, { duration: 120 });
  }}
>
  <box style={animatedProps({ scale })}>
    <text>Press me</text>
  </box>
</gestureDetector>;
```

Keep the detector around the smallest subtree that needs the interaction. Use `onFinalize` to
restore the visual state when the gesture ends or is cancelled.

## Styling best practices

* Prefer `padding` over `margin` for scrollable and pager edge spacing.
* Prefer `spacing` on a parent row or column for consistent child gaps.
* Use `weight` for proportional space in linear layouts.
* Use `clip` when rounded corners should clip child content.
* Keep layout values stable and use React state for visual changes.
* Do not rely on `style.transition` for pressed or selected interaction feedback; use
  `gestureDetector` with shared values and `animatedProps` when feedback must animate.
