Bram

A simple 4kB web components library

Bram logo

Bram

Install the latest:

npm install bram@next --save

Or download a release.

Examples

Todo app


<template id="todo-template">
<form @submit="{{addTodo}}">
  <input type="text" name="todo"
    placeholder="What to do?">
  <button type="submit">Add</button>
</form>

<ul>
  <template directive="foreach"
    expression="todos">
    <li>{{item}}</li>
  </template>
</ul>
</template>

class ViewModel {
  constructor() {
    this.todos = [];
  }
  
  addTodo(ev) {
    ev.preventDefault();
    let input = ev.target.todo;
    let value = input.value;
    this.todos.push(value);
    input.value = '';
  }
}

const template = document
  .querySelector('#todo-template');

class TodoList extends Bram.Element {
  constructor() {
    super();
    this.attachView(template, new ViewModel());
  }
}

customElements.define('todo-list', TodoList);
            

GitHub Pull Requests


<template id="my-tmpl">
<github-prs repo="matthewp/bram"
  limit="3"></github-prs>

<h1>Latest PRs</h1>
<ul>
  <template directive="foreach"
    expression="prs">
    <li>
      ({{state}})

      <a href="{{url}}">{{title}}</a>
    </h1>
  </template>
</ul>
</template>

<div id="bram-info"></div>                
            

class GitHubPRs extends Bram.Element {
  connectedCallback() {
    let repo = this.getAttribute('repo');
    let limit = this.getAttribute('limit') || 5;
    this.fetch(repo, limit);
  }

  fetch(repo, limit) {
    let url = `https://api.github.com/repos/
    ${repo}/pulls?page=1&per_page=${limit}
    &state=all`;

    fetch(url).then(res => {
      return res.json();
    }).then(results => {
      results.forEach(pr => {
        let ev = new CustomEvent('pullrequest', {
          detail: pr
        });
        this.dispatchEvent(ev);
      });
    });
  }

  set onpullrequest(value) {
    if(this._onpullrequest) {
      this.removeEventListener('pullrequest',
      this._onpullrequest);
    }
    this._onpullrequest = value;
    this.addEventListener('pullrequest', value);
  }
}

customElements.define('github-prs', GitHubPRs);

let myTemplate = document.querySelector('#my-tmpl');
let instance = createInstance(myTemplate, {
  prs: []
});

let root = document.querySelector('#bram-info');
root.append(instance.fragment);

let gh = document.querySelector('github-prs');
gh.onpullrequest = ev => {
  let pr = ev.detail;
  instance.model.prs.push(pr);
};
            

Advantage

Minimal layer

Bram supplies only a minimal layer on top of the native web component standards; <template>, Custom Elements, and Shadow DOM.

Bram allows you to still use these APIs, but enhances their capabilities, providing important missing pieces like template bindings.

Declarative

Templates within Bram are completely declarative. You can bind to text and attributes. You can pass values to child components through property bindings. You can listen to events in any element and have those events call your components methods.

Tiny

Thanks to the web component APIs doing all of the heavy lifting, Bram gives you a lot, for very little. At 3kB you can use Bram to distribute widgets and not feel bad about it.