Joy DOM

Styling

Selectors, resolution order, and inline overrides.

The business card from chapter 1 is functional but bland. This chapter adds visual polish using Joy DOM's three selector types and explains how rules compose when several apply to the same node.

The three selectors

SelectorExampleMatches
TypepNodes with type: "p".
Class.titleNodes whose className array includes title.
Id#heroNodes with id: "hero".

Use type selectors for global defaults (every paragraph, every heading), classes for reusable patterns (.card, .row), and ids for one-off targeting (#hero, #footer).

Polish the card

Add a border, accent the headline color, and align the meta text:

{
  "version": 1,
  "style": {
    ".card": {
      "display": "flex",
      "flexDirection": "column",
      "gap": {
        "value": 4,
        "unit": "px"
      },
      "padding": {
        "value": 24,
        "unit": "px"
      },
      "backgroundColor": "#ffffff",
      "borderWidth": {
        "value": 1,
        "unit": "px"
      },
      "borderStyle": "solid",
      "borderColor": "#e2e8f0",
      "borderRadius": {
        "value": 12,
        "unit": "px"
      }
    },
    "h1": {
      "display": "flex",
      "fontSize": {
        "value": 28,
        "unit": "px"
      },
      "color": "#0f172a",
      "fontWeight": "bold"
    },
    "p": {
      "display": "flex",
      "fontSize": {
        "value": 14,
        "unit": "px"
      },
      "color": "#475569"
    },
    ".meta": {
      "display": "flex",
      "textTransform": "uppercase",
      "letterSpacing": {
        "value": 1,
        "unit": "px"
      }
    }
  },
  "breakpoints": [],
  "layout": {
    "type": "div",
    "props": {
      "className": ["card"]
    },
    "children": [
      {
        "type": "h1",
        "children": ["Avery Chen"]
      },
      {
        "type": "p",
        "props": {
          "className": ["meta"]
        },
        "children": ["Product designer · Tokyo"]
      }
    ]
  }
}

Two things are worth noticing:

  • p and .meta both apply to the meta paragraph. Class selectors run after type selectors, so .meta overrides any conflicting property without needing inline styles.
  • The h1 rule sets only the typography for the heading; the parent .card already drives layout.

Resolution order

When multiple rules touch the same node, Joy DOM applies them in this order, with later sources overriding earlier ones:

  1. Type selector.
  2. Class selectors, in the order listed in className.
  3. Id selector.
  4. Breakpoint styles when a matching breakpoint activates.
  5. Inline props.style.

So className: ["meta", "highlight"] applies .meta first, then .highlight - the later class wins on shared properties.

Inline styles for one-offs

When a node needs a value that should not be reused, set it inline:

{
  "type": "p",
  "props": {
    "className": ["meta"],
    "style": {
      "display": "flex",
      "color": "#16a34a"
    }
  },
  "children": ["Available for new projects"]
}

props.style wins over every shared selector. Reach for it sparingly - most styles should live on a class so they're easy to reuse.

Color values

Joy DOM colors are hex strings. rgb() and rgba() are not supported. If you need partial transparency, use the opacity property - see §5.7.2.

Wrap-up

The card has its visual identity. Next we make it adapt to its container with breakpoints.

Spec references: §4 Styles · §5 Properties

On this page