Blackberry.js

A zero-build html component library for the artisanal web.

Overview

Blackberry is a small frontend library providing reactivity, composability, scoped styles, and a simple API to make webdev fun again.

Blackberry.js is inspired by Strawberry.js, and is designed to be used as a lightweight html-first alternative to frameworks like Vue and Svelte without requiring build tooling or a complex dependency tree.

Guide

Blackberry has a very simple API. Components are defined using the template tag with a blackberry attribute signifying the component name, which must contain a hyphen. Inside of the template, you can define elements the component should render, a script tag for state and logic, and a style tag for styling.

Setup

Include the Blackberry.js script in your html file. Calling Blackberry.start() parses and registers any components defined in the document. Subsequent components can be defined in the document and Blackberry will automatically register them.

Optionally, you can put a blackberry-cloak attribute on the document body and style it so that it remains hidden until blackberry has parsed and registered all components, in which case it will remove the attribute.

Script Tag

Blackberry components can define a top level script tag, which acts similarly to the script tag in Vue or Svelte components. It can be used to define reactive state, effects, cleanup functions, and access the underlying dom element of the component.

State

Code inside of the script tag has access to a $state object which can be used to store reactive data. Any changes to the state will trigger a re-render of the component. This data can be directly accessed inside of the component's template.

Attributes

Attributes are values that can be passed into a component. They can be defined on a component's template tag using a comma seperated attributes attribute, and accessed via the reactive $attributes object.

Effects

The effect function is available inside of the script tag via the $effect value. They are automatically run when the component is rendered and whenever a reactive value inside the scope of the callback changes.

Templating

Templates can use directives to bind data to elements, listen for events, and conditionally render elements. Directives are javascript expressions that are evaluated in the context of the component.

Attributes

The : directive binds the value of the expression to the attribute. Example: :foo="`the count is ${count}`" will set the attribute foo to the value of the expression.

Text

The :text directive binds it's value as the text content of the node.

If

The :if directive conditionally renders the node based on the value of the expression.

HTML

The :html directive binds it's value as the innerHTML of the node. Be careful when using this directive as it can be a security risk.

Ref

The :ref directive binds the value of the dom element to the ref's value property.

Events

The @ directive binds it's value as an event listener. Example: @click="increment"

Lists

The each directive renders a list of elements for each item in an array. It must be used on a template tag, and follows the format each:item="items".

Property Directive

The . directive binds the value of the expression to the element as a property. This is useful for passing values other than strings to components or setting properties on elements.

Slots

Slots are used to pass content into a component. They are defined in the component's template using the slot tag. The content passed into the slot is rendered in place of the slot tag.

Styling

Styles can be defined in the style tag of a component. Styles are scoped to the component and do not leak out.

Because Blackberry components use the shadow-dom, they do not have access to global stylesheets by default. If you want your component to inherit styles from the outside document, you can set the global-styles attribute on a component template.

Why did you make this?

I wanted a way to write reusable components while authoring HTML without needing to set up a build pipeline or pull in dependencies and additional JS. I wanted something I could use to "sketch" in HTML without the cognitive overhead of switching to JS.

How does it work?

Blackberry uses the shadow-dom to encapsulate styles and isolate components. When compiling a template, it extracts the script and style tag contents and builds a vdom structure of the template. It then uses the vdom, style, and script content to create a custom ivysaur component and registers it with the browser.

Who should use this?

Anyone who wants to :) I wouldn't use this if I was building a very large or complex web application (I would use ivysaur), but for smaller websites that are written either in plain HTML or in a non-javascript templating language, blackberry can be a good choice. It's small size means it's reasonable to include in a project even for just a handful of components or uses.

Douglas Crockford on the XML of today

It’s probably the JavaScript frameworks. They have gotten so big and so weird. People seem to love them. I don’t understand why. The browsers have actually gotten pretty good. The web standards thing have finally worked, and the web API is stable pretty much. Some of it’s still pretty stupid, but it works and it’s reliable.
Read the transcript on Corecursive