Skip to content
Kyle Robinson Young edited this page Mar 3, 2016 · 28 revisions

bel is a simple element creator. It returns pure DOM elements but still uses efficient DOM diffing to update.

Because bel creates native DOM elements, they run standalone. No need to constantly update to keep in step with a framework or separate rendering library. Spend that time making each element do one thing better and better.

Tagged Template Strings

bel uses tagged template strings to compose elements. They are part of the JavaScript language and are available in modern browsers. There are build tools (like hyperxify) to compile for older browser targets.

Compose an Element

// Require bel
var bel = require('bel')

// Compose an element
var element = bel`<div>Hello!</div>`

// Add to the page
document.body.appendChild(element)

Compose Multiple Elements

With template strings, anything between the curly braces ${} is JavaScript:

var bel = require('bel')

var bears = ['grizzly', 'polar', 'brown']
var element = bel`<ul>
  ${bears.map(function (bear) {
    return bel`<li>${bear}</li>`
  })}
</ul>`

document.body.appendChild(element)

Attributes and Events

Attributes and event handlers can be added to elements in a natural way:

var button = bel`<button classs="primary" onclick=${function (e) {
  alert('button was clicked!')
}}>click me</button>`

Styling Elements

Specifying a style attribute will set the inline style in a Content Security Policy friendly way, using dom-css:

var css = {
  backgroundColor: 'red',
  transform: 'rotate(90deg)'
}
var element = bel`<div style=${css}>Hello!</div>`

It will even vendor prefix style properties that need it, like transform!

Updating an Element

When your element has changed, call it's .update() function to replace the element with a new one using DOM diffing:

var element = bel`<div>hello</div>`

// ... later ...

element.update(bel`<div>changed!</div>`)

Data Down

Any time the data changes, re-render your element with the new data:

function render (msg) {
  return bel`<div>${msg}</div>`
}
var element = render('hello')

// ... later ...

element.update(render('changed!'))

Scaling

As your element grows more complex, simply move that portion to another function and keep passing the data down:

var bears = ['grizzly', 'polar', 'brown']
var element = render(bears)

function render (bears) {
  return bel`<ul>
    ${bears.map(function (bear) {
      return bel`<li>${button(bear)}</li>`
    })}
  </ul>`
}

function button (label) {
  return bel`<button>${label}</button>`
}

Actions Up

When an event occurs and/or your data needs to change, send up an action:

var bears = ['grizzly', 'polar', 'brown']

// First render a list of bears without any selected
var element = render(bears, 'No Bear Selected')

// We pass down all the values needed to render
function render (bears, selectedBear) {
  return bel`<ul>
    <li><strong>${selectedBear}</strong></li>
    ${bears.map(function (bear) {
      return bel`<li>${button(bear, selectBear)}</li>`
    })}
  </ul>`
}

// When a bear is selected, we update the element with the newly selected bear
function selectBear (bear) {
  element.update(render(bears, bear))
}

// This button doesn't need to know about the above code
// This element focuses on doing one thing, being a button
function button (label, onselected) {
  return bel`<button onclick=${function () {
    onselected(label)
  }}>${label}</button>`
}

Coming Soon

These are some planned features to hopefully be implemented soon:

SVG

SVG elements require a namespace and need a little bit of special handling. Eventually the goal is to handle them seamlessly like any other HTML tag:

var r = 50
var svg = `<svg width="100" height="100" viewBox="0 0 100 100">
  <circle r="${r}" cx="${r/2}" cy="${r/2}" fill="red" />
</svg>`

https://github.com/shama/bel/issues/1

Onload / Onunload

Clone this wiki locally