Skip to main content

Installation

Solar is runtime-based — no compiler, no build step required. Scaffold a new project with one command, or drop it into any HTML file via CDN.
npm create solarbuild@latest my-app
This creates a my-app/ directory with everything wired up:
my-app/
├── index.html
├── main.js
├── package.json
├── solar/          # Solar framework (local copy)
└── components/
    └── App.js
Then:
cd my-app
npm run dev
Open http://localhost:3000 — your app is running.

The fastest way to get running. Import Solar directly from a CDN in any HTML file:
<!DOCTYPE html>
<html>
  <head><title>My Solar App</title></head>
  <body>
    <div id="app"></div>
    <script type="module">
      import { defineComponent, mountComponent, useState, createElement } from 'https://cdn.jsdelivr.net/npm/solarbuild/framework/index.js'

      const App = defineComponent({
        name: 'App',
        props: {},
        render() {
          const [count, setCount] = useState(0)
          return createElement('div', {},
            createElement('p', {}, `Count: ${count}`),
            createElement('button', { onclick: () => setCount(c => c + 1) }, '+'),
          )
        },
      })

      mountComponent(App, {}, document.getElementById('app'))
    </script>
  </body>
</html>
No install, no config. Open the file in a browser and it works.

npm

For projects using a bundler (Vite, Rollup, esbuild):
npm install solarbuild
Then import from the package directly:
import { defineComponent, mountComponent, useState, createElement } from 'solarbuild'

Project structure

Solar enforces a rigid file structure so that generated components are always predictable:
my-app/
├── index.html
├── main.js           # mounts root components
└── components/
    ├── Button.js     # one component per file
    ├── Counter.js
    └── UserCard.js
Rules:
  • One component per file
  • File name matches the component name
  • Default export is always the defineComponent call

Your first component

Every component is defined through a schema that declares its shape explicitly:
import { defineComponent, createElement, registry } from 'solarbuild'

const Button = defineComponent({
  name: 'Button',
  props: {
    label: { type: 'string', required: true },
    onClick: { type: 'function', required: true },
    variant: { type: 'string', enum: ['primary', 'secondary'], default: 'primary' },
  },
  render({ label, onClick, variant }) {
    return createElement('button', { class: variant, onclick: onClick }, label)
  },
})

registry.register(Button)
export default Button
If a prop contract is violated, Solar throws a structured error immediately:
{
  "error": "ContractError",
  "component": "Button",
  "prop": "label",
  "expected": "string",
  "received": "number",
  "fix": "Pass a string value for \"label\"",
  "message": "Button: prop \"label\": expected string, got number"
}

Mounting to the DOM

Use mountComponent to attach a component to a DOM node:
import { mountComponent } from 'solarbuild'
import Button from './components/Button.js'

mountComponent(Button, {
  label: 'Click me',
  onClick: () => console.log('clicked'),
  variant: 'primary',
}, document.getElementById('app'))