Components

In JAF, a component is an HTML file.

There is no special file extension, no build configuration, and nothing to import.

Basic Structure

A component is any .html file with a PascalCase filename.

The filename becomes the tag name, so Button.html gives you <Button />.

<!-- pages/components/Button.html -->
<script>
let count = 0
</script>

<button onclick="count++">Clicked {count} times</button>
output

Use it anywhere, without importing it:

source
<!-- pages/index.html -->
<h1>Welcome</h1>

<Button />

The Three Parts

Components have three optional sections, in any order:

  • <script> - JavaScript logic, reactive variables, functions
  • Template - HTML markup with JEX expressions
  • <style> - CSS that's scoped to this component by default

All three are optional. A component can be nothing but markup:

source
<!-- pages/components/Logo.html -->
<svg viewBox="0 0 100 100" width="40" height="40" aria-label="Logo">
  <circle cx="50" cy="50" r="40" fill="currentColor" />
</svg>
output

Auto-Discovery

JAF scans your project for components.

Any .html file whose name starts with an uppercase letter is a component; lowercase files under pages/ are routes. Both kinds of file can sit side by side.

my-app
index.htmlPage - /
about.htmlPage - /about
Banner.htmlComponent - <Banner />
Button.htmlComponent - <Button />
Card.htmlComponent - <Card />
index.htmlPage - /dashboard
StatsCard.htmlComponent - <StatsCard />

Select a file to see what it is for

Every component in that tree is available in every page and every other component, under its filename.

components/ is a convention for keeping them together, not a requirement - StatsCard.html next to the dashboard page works exactly the same.

Duplicate Names

Where a file sits only matters when two components share a name. The shallower path wins - pages/Button.html beats pages/admin/Button.html - and a file in the root components/ folder is the last resort.

Two files claiming one name at the same depth is a build error naming both: nothing can decide between them. Rename one, or steer one into a namespace.

No Component Imports

Most frameworks make you register a component before you can use it. JAF has no equivalent: there is no import Button from "./components/Button.html", and writing one leaves Button undefined.

Discovery by filename is the whole mechanism.

source
<script>
// JAF has no component import. This line does nothing:
//   import Button from "./components/Button.html"
</script>

<!-- Button.html is found by filename - just use the tag. -->
<Button />

Naming a file on the tag is a build error

The alpha let a tag name its own file, so any tag name could be pointed at any component:

source
<!-- Every one of these is a build error now -->
<MyButton file="/pages/lib/ui/Button.html" />
<LocalWidget file="./widgets/Special.html" />
<SubmitBtn file="/pages/components/Button.html" />

A component is resolved to a module when the build runs, and a path only resolves once the app does. So the tag has to name a component the build compiled.

Move the file to where the name resolves, or give it the name you want to write. When two components genuinely need the same name, tell them apart with namespaces.

Imports in Scripts

Standard ES imports work in a component's <script> for npm packages:

source
<script>
import { codeToHtml } from 'shiki'
import _ from 'lodash'
import debounce from 'lodash/debounce'

let code = ''
</script>

At compile time, JAF resolves package specifiers to Vite's pre-bundled deps.

The imported values are available throughout your component.

Note: imports are for JavaScript modules. Other JAF components never need one - they are found by filename.