opjsx

Interpolation

Inject dynamic values, event handlers, and lists with ${…}.

Because opjsx is a tagged template, you use ordinary ${…} to inject JavaScript. Interpolations are preserved through parsing and substituted back as real values, so their type is kept intact.

Dynamic values

const name = "Ada";

opjsx`
  &h1
    Hello ${name}
  &input value"${name}"
`;

A value that is exactly an interpolation keeps its JS type (string, number, etc.). An interpolation embedded in surrounding text is stringified, e.g. &div.price $${product.price}"$129.99".

Event handlers

Functions pass straight through:

opjsx`
  &button.cta onClick"${() => alert("clicked")}"
    Click me
`;

Since the handler lives inside ${…}, it's evaluated by JavaScript before opjsx ever sees it — its inner quotes and braces never confuse the parser.

Moving a handler into ${…} loses JSX's contextual typing, so type the event param yourself: onChange"${(e: ChangeEvent<HTMLInputElement>) => setValue(e.target.value)}".

Lists with .map()

Return an array of opjsx elements from .map() and interpolate it as a child. Nested opjsx results pass through untouched:

const items = [
  { id: 1, name: "Alpha" },
  { id: 2, name: "Beta" },
];

opjsx`
  &ul.list
    ${items.map((item) => opjsx`
      &li key"${item.id}"
        ${item.name}
    `)}
`;

Dynamic classes

A conditional class can't use the dot shorthand (the value is computed), so fall back to the className"…" attribute:

opjsx`
  &div className"card ${isActive ? "active" : ""}"
    ...
`;

Continue to the API.