Skip to content

Tag props

When you declare a view in a layout with a jops tag, the tag’s other attributes are passed to the view as props. It works like Android’s AttributeSet for a custom view declared in XML, or like React props, except that the values are always strings.

src/layout/dashboard.html
<section class="dashboard">
<Card jops src="/src/Card.js" title="Monthly report" item-id="42" variant="compact"></Card>
<Card jops src="/src/Card.js" title="Open tasks" item-id="7"></Card>
</section>

The same Card class is used twice, each time with its own props.

src/Card.js
import { View, layout } from "jops-core";
export default class Card extends View {
constructor() {
super();
// props are available right after super()
this.layout = layout`
<article class="card ${this.props.variant ?? ""}">
<h3>${this.props.title}</h3>
</article>`;
this.inflate();
}
onLayout() {
this.itemId = Number(this.props.itemId); // "42" → 42
}
}

Props are available right after super() in the constructor, in an overridden loadLayout() and in onLayout(). The constructor needs no parameters for this: props reach a declared view whatever its constructor looks like.

  • camelCase names. Attribute names are converted to camelCase: item-id becomes itemId, data-x becomes dataX.
  • String values. Values are always strings. Convert them yourself (Number(this.props.itemId), this.props.open === "true").
  • Read-only. this.props is a frozen object, and {} when the tag has no props.
  • Reserved attributes. jops, type="jops", src, layout, path and jops-event-bind belong to JOPS and are not props.
  • id, class and on* are props only. They are not copied to the view’s element, and an onclick prop is not bound to anything. If your view should use them, apply them yourself.
<Card jops src="/src/Card.js" id="card1" class="wide" onclick="onOpen" title="Hi"></Card>
// this.props → { id: "card1", class: "wide", onclick: "onOpen", title: "Hi" }

Props come from the jops tags in any layout JOPS renders:

  • the root layout,
  • the Router’s route declarations (<Users jops path="/users" src="…" mode="compact">),
  • a route’s own layout,
  • the layouts of declared views,
  • the layouts of views added with addSubView() or insertSubView().

A view you create yourself with new has no tag, so it gets its data another way:

// 1. Constructor arguments: the usual way for your own classes
await this.addSubView("items", new TaskItem(task));
// 2. Props through the base constructor
const note = new View(layout`<p>Note</p>`, { title: "Hi" });
// 3. In a subclass, pass props to super()
class Badge extends View {
constructor(label) {
super(undefined, { label });
}
}

Constructor arguments can be any JavaScript value. Props passed this way follow the same read-only rule as tag props.