Getting Started
Build a complete LOSOS app in 5 minutes. No npm. No build tools.
1. Get the files
Create a project directory and copy the framework files:
my-app/
losos/
html.js ← from losos.org/losos/html.js
store.js ← from losos.org/losos/store.js
shell.js ← from losos.org/losos/shell.js
lion/
index.js ← from losos.org/lion/index.js
panes/
my-pane.js ← you write this
data.jsonld ← you write this
index.html ← you write this
2. Create the data
A JSON-LD file with @context mapping short keys to standard URIs:
{
"@context": {
"schema": "http://schema.org/",
"dct": "http://purl.org/dc/terms/",
"title": "dct:title",
"item": "schema:hasPart",
"name": "schema:name",
"done": "schema:status",
"List": "schema:ItemList",
"Item": "schema:ListItem"
},
"@id": "#this",
"@type": "List",
"title": "My List",
"item": [
{ "@id": "#1", "@type": "Item", "name": "First item", "done": false },
{ "@id": "#2", "@type": "Item", "name": "Second item", "done": true }
]
}
3. Create the pane
A pane is an ES module with canHandle and render:
import { createStore } from '../losos/store.js'
import { html, render, onUnmount, keyed } from '../losos/html.js'
export default {
label: 'My App',
icon: '📋',
canHandle(subject, store) {
var node = store.get(subject.value)
var type = store.type(node)
return type && type.includes('List')
},
render(subject, lionStore, container, rawData) {
var data = rawData
var store = createStore(data, { debounce: 800 })
var root = store.get('#this')
function renderApp() {
var items = store.propAll(root, 'item')
render(container, html`
<h1>${data['title']}</h1>
<input type="text" placeholder="Add item..."
onkeydown="${function(e) {
if (e.key !== 'Enter') return
store.push(root, 'item', {
'@id': '#' + Date.now(),
'@type': 'Item',
'name': e.target.value,
'done': false
})
e.target.value = ''
}}" />
${keyed(items, function(i) { return i['@id'] }, function(i) {
return html`
<div>
<input type="checkbox"
checked="${i['done']}"
onchange="${function() { store.set(i, 'done', !i['done']) }}" />
${i['name']}
</div>
`
})}
`)
}
var unsub = store.onChange(renderApp)
setTimeout(renderApp, 0)
onUnmount(container, unsub)
}
}
4. Create the HTML shell
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My App</title>
</head>
<body>
<script type="application/ld+json" src="data.jsonld"></script>
<script type="module" data-pane src="panes/my-pane.js"></script>
<div id="losos"></div>
<script type="module" src="losos/shell.js"></script>
</body>
</html>
5. Open in browser
Serve with any static server:
npx serve .
# or
python3 -m http.server
That's it. No npm install, no build, no configuration.
What happens when you load the page
- Shell scans for
<script data-pane>tags and loads each pane module - Shell fetches
data.jsonldinto a LION store - Shell finds the primary subject (
#this), checks each pane'scanHandle - Shell builds a tab bar and renders the first matching pane
- Shell passes the parsed JSON-LD as the 4th argument to
render
Adding persistence
To auto-save changes to a Solid pod or any HTTP server that accepts PUT:
var store = createStore(data, {
url: 'https://my-pod.example/data.jsonld',
authFetch: window.xlogin.authFetch,
debounce: 800
})
Every store.set() now debounces a PUT request. If the server sends an Updates-Via header, the store auto-subscribes to WebSocket updates.
Next steps
- API Reference — every function in detail
- Gotchas — read before your second app
- Examples — 5 complete apps to learn from