PTMLHomeGetting StartedReference

Getting Started

PTML is a declarative markup language that compiles to React components. This guide takes you from install to working prototype.

Installation

Install the package with npm. PTML requires React 18 or later as a peer dependency.
npm install ptml
Source code and issue tracker are on GitHub at github.com/axzr/ptml.

Quick Setup

PTML works inside any React app. Import the hook, pass it a PTML string, and render the result:
import { usePtmlRender } from 'ptml';.const ptml = `ptml:> text: Hello, world!`;.function App() { const { node, error } = usePtmlRender(ptml); if (error) return <pre>{error}</pre>; return <>{node}</>;}
That is the entire integration. PTML handles parsing, validation, state management, and rendering internally.

API Reference

The package exports four main functions:
usePtmlRender(ptml, options?)React hook. Returns { node, error }. Re-renders when the PTML string changes. Pass { files } in options for multi-file projects.
validate(ptml)Returns { isValid: true } or { isValid: false, errorMessage: string }. Use for editor tooling or pre-flight checks.
render(ptml)Returns a React node directly, or null on failure. Simpler than the hook but does not support state re-renders.
parse(ptml)Returns the raw AST (array of root nodes). Useful for building tooling or inspecting PTML structure programmatically.

Multi-File Projects

PTML supports importing templates and styles from other files. Pass a files map as the second argument to the hook:
import { usePtmlRender } from 'ptml';import mainPtml from './main.ptml?raw';import sharedPtml from './shared.ptml?raw';.const files = { 'shared.ptml': sharedPtml,};.function App() { const { node, error } = usePtmlRender(mainPtml, { files }); return <>{node}</>;}
The keys in the files map match the filenames used in import: declarations inside your PTML code. Vite's ?raw suffix imports files as strings.

Node Categories

Every line in PTML is a node. Nodes are organized into categories, each with its own prefix character:
>Blocks are renderable UI elements: box, text, button, header, input, textarea, form, list, and more.
-Properties configure their parent node: styles, click, value, type, href, role, and CSS properties.
?Conditionals control rendering and styling: if and else.
!Actions modify state: set, clear, call, and list operations like addValue and removeValue.
Root-level declarations like state:, ptml:, define:, and template: have no prefix. They sit at the left edge of the file.

Your First PTML

The simplest PTML file has a ptml: declaration containing block nodes:
ptml:> box: > text: Hello, world!
This renders a div containing the text "Hello, world!". The box node creates a container and the text node displays content.

Adding State

Declare state variables with the state: root node. Reference them in text with the dollar sign prefix:
state:- name: World.ptml:> text: Hello, $name!
The $name token is replaced with the value "World" at render time. State supports strings, numbers, booleans, null, and nested objects.

Interactivity

Add click handlers to buttons to update state. Actions like set change state values:
state:- greeting: Hello.ptml:> text: $greeting> button: > text: Say goodbye - click: ! set: greeting Goodbye
Clicking the button sets the greeting state to "Goodbye", and the text updates automatically.

Styling

Apply CSS properties to any node with inline styles or reusable named styles:

Inline Styles

ptml:> text: Styled text - styles: - color: #2563eb - font-weight: bold

Named Styles

Define reusable style sets with the define: declaration and reference them by name:
define: primary-text- color: #2563eb- font-weight: bold.ptml:> text: Styled text - styles: primary-text

Conditionals

Use if and else to conditionally render content based on state:
state:- loggedIn: true.ptml:> box: ? if: $loggedIn > text: Welcome back! ? else: > text: Please log in.
The if condition supports truthiness checks, the is operator for equality, and special keywords like empty and not empty.

Templates

Define reusable components with the template: declaration and render them with show:
template: greeting-card> box: > header: h2 > text: Hello! > text: Welcome to the site..ptml:> show: greeting-card
Templates can accept arguments and be imported from other files, enabling modular PTML projects.

Styling part of a sentence

A text node can contain further text nodes. They render as inline runs of the same paragraph, so one word can be styled differently without breaking the line up:
> text: Open from > text: 9am - styles: - color: magenta > text: to 5pm
Because the runs are genuinely inline, the browser handles wrapping, line height and the width of a space. Do not reach for a flex row of boxes instead: a gap applies to both axes, so wrapped lines gain unwanted vertical space, and the horizontal gap is only ever a guess at how wide a space should be.

Whitespace in text

Exactly one space after the colon separates a node from its text. Any further leading spaces are part of the text, which is how each inline run above is spaced away from the one before it, and how the code samples on this page keep their indentation.
> text: no leading space> text: one leading space kept> text: two leading spaces kept
Trailing spaces are always stripped. They are invisible in the source and most editors remove them on save, so no document should depend on them. Where a space is needed between two runs, put it at the start of the following run.