opjsx

Syntax

The opjsx markup grammar — elements, classes, attributes, nesting, and text.

A opjsx template is indentation-based. Each element is one line; its children are the more-indented lines beneath it. There are no closing tags.

Elements

Every element line starts with &:

&div
&header
&my-custom-element

The & marker is what distinguishes an element from text, so any tag name works — including custom elements. A line that does not start with & is treated as a text child.

Classes

Use Emmet-style dot shorthand for className:

&div.card
&div.card.active
&button.btn.btn-primary

&div.card.active<div className="card active">. Dots separate classes; hyphens live inside a class name (&div.nav-container is one class, nav-container).

Attributes

Attributes are name"value" — no = sign:

&input type"text" placeholder"Search..." name"q"
&a href"/about"

Values are typed: tabIndex"3" → number 3, hidden"true" → boolean true. A .class shorthand and a className"…" attribute can coexist; they merge.

Nesting

Indentation defines the tree. No closing tags:

&section.hero
  &div.content
    &h1
      Big title
    &p
      Some copy

Text children

Any indented line that doesn't start with & is a text node:

&h1
  Welcome to the site
&p
  A paragraph of plain text.

Putting it together

&article.post
  &h2.post-title
    Hello
  &div.post-body
    &p
      First paragraph.
    &p
      Second paragraph.

renders to:

<article class="post">
  <h2 class="post-title">Hello</h2>
  <div class="post-body">
    <p>First paragraph.</p>
    <p>Second paragraph.</p>
  </div>
</article>

Next: making it dynamic with Interpolation.