Skip to content

RFC: v0.2 phase 3 — style block, behavior verbs, components #93

Description

@andreahlert

RFC: v0.2 phase 3 — style block, behavior verbs, components

Part of umbrella #80. Depends on phase 1 (#91) and phase 2 (#92). Largest surface, highest risk.

Summary

Three related primitives:

  1. style block with intent selectors (by role / variant, never by route path).
  2. Behavior verbs: closed vocabulary of imperative verbs on on <event>: blocks that compile to a small generated JS bundle.
  3. component <name>: parametrized, stateless render template (rename pending, see open questions).

1. Style block with intent selectors

Intent selectors address elements by their semantic role or variant, not by route path or class name.

style
  variant primary
    bg: blue-600
    fg: white
    radius: md

  variant danger
    bg: red-600
    fg: white

  role heading
    size: xl
    weight: bold

  role metric
    size: 2xl
    tabular: true

Closed value scales:

  • Color tokens (e.g., blue-600, red-600, neutral-100).
  • Spacing tokens (0–10).
  • Size enum (xs / sm / md / lg / xl / 2xl).

Raw CSS escape hatch, consistent with query: """ ... """ for SQL:

style
  raw: """
  @keyframes spin { from { transform: rotate(0) } to { transform: rotate(360deg) } }
  """

Rejected alternative from the original RFC: selecting by route path (action /tasks/:id/delete) couples visual styling to URL structure. Renaming a route would silently break styling. Dropped in favor of role/variant only.

2. Behavior verbs

Closed imperative vocabulary attached via on <event>: blocks. Compiles to a small generated JS bundle served next to htmx.min.js.

Events: click, submit, success, error, hover, focus, blur.

Verbs: show, hide, toggle, toast, redirect, swap, focus, disable, enable, confirm, copy, wait, then.

Animation verbs: fade, slide, bounce, pulse, shake.

button action="/tasks/{t.id}/delete" confirm
  "Delete"
  on success
    toast "Task deleted"
    fade self

3. Components (stateless render templates)

component task_card t
  row card pad=3 align=center
    check t.done action="/tasks/{t.id}/toggle"
    text t.title strike=t.done
    button action="/tasks/{t.id}/delete" variant=danger size=sm "X"

page /tasks
  query tasks: SELECT * FROM task WHERE owner = :current_user.id
  stack pad=4 gap=3
    each tasks as t
      task_card t

Components have no state and no behavior of their own. They are pure template functions.

Depends on

Open questions

  • Naming: "component" vs. "template" / "partial". "Component" will mislead users coming from React, who expect state and lifecycle. Proposal: rename to template or partial.
  • Component parameter typing. Should params be typed against a model definition? Proposal: yes, optional type annotation: component task_card t: task.
  • Theme reuse. Should style blocks be importable across files for shared design systems? This conflicts with Principle 5 (one file = complete app). Proposal: no cross-file style imports in v0.2; revisit if real demand appears.
  • Behavior verb runtime surface. 7 events × 14 verbs × 5 animations is a significant JS codegen surface. Needs cross-browser test matrix, htmx event model compatibility check, and a debugging story.
  • Animation verbs. May be out of scope entirely. Candidate for dropping from phase 3 and revisiting when a concrete need surfaces.

Success criteria

  • kiln-studio rewritten to use style + components; LOC drops measurably vs. current approach.
  • Behavior verb JS bundle under 5 KB gzipped.
  • No user-written <script> tags in examples/ except inside script raw: escape hatches.

Decision gate

Do not start phase 3 until phases 1 and 2 have shipped and been used by real apps. The vocabulary choices here depend on concrete pain points observed in practice, not speculation.

Rejected alternatives

  • Intent selectors by route path: breaks on route renames.
  • Stateful components: scope creep; socket and stream already cover reactive needs.
  • Open-ended behavior verbs (any JS expression): defeats the closed-vocabulary premise.

Metadata

Metadata

Assignees

Labels

area/analyzerType checking and static analysisarea/parserRecursive descent parserarea/runtimeHTTP server and AST interpreterkind/rfcDesign proposal, RFC under discussionstale

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions