LivingBlocks · v0.4.1 · MIT

Components as data.

A carousel, an accordion or a ring, written as data: layers with roles, the parts its behaviour needs, its settings. Any design draws it in its own style; a small runtime makes it work, with a keyboard and a screen reader. Free for everyone.

npm install livingblocks
  • 11.3 KB runtime, gzipped
  • 0 dependencies
  • 7 behaviours
  • 16 Blocks

Picture 1

A line about this picture.

Picture 2

A line about this picture.

Picture 3

A line about this picture.

This carousel: data-living='{"kind":"carousel","v":1,"settings":{"perView":1,"loop":true,"autoplay":false,"interval":5,"arrows":true,"dots":true,"swipe":true,"start":0,"parallax":0.12}}'

The idea

One Block, three ways.

A Block is a file of data. A design draws it in its own style and marks the parts; the runtime reads those marks and makes it work. Nothing in the file runs.

blocks/faq.json in the package: layers with roles, the parts the behaviour needs, its settings. No code.

{
  "$schema": "../schema/block.schema.json",
  "format": 1,
  "id": "faq",
  "kind": "accordion",
  "label": "FAQ list",
  "hint": "A plain list of questions and answers between hairlines, all closed until opened",
  "category": "content",
  "isNew": true,
  "settings": {
    "single": false,
    "start": -1
  },
  "root": {
    "type": "stack",
    "name": "FAQ list",
    "w": 640,
    "h": 520,
    "layout": {
      "direction": "column",
      "gap": 0,
      "pad": [0, 0, 0, 0],
      "align": "stretch"
    },
    "sizeW": "fixed",
    "sizeH": "fit",
    "children": [
      {
        "type": "stack",
        "name": "Item {n}",
        "part": "item",
        "w": 640,
        "h": 124,
        "repeat": 4,
        "layout": {
          "direction": "column",
          "gap": 0,
          "pad": [0, 0, 0, 0]
        },
        "sizeW": "fill",
        "sizeH": "fit",
        "clip": true,
        "children": [
          {
            "type": "stack",
            "name": "Header",
            "part": "header",
            "w": 640,
            "h": 60,
            "layout": {
              "direction": "row",
              "gap": 16,
              "pad": [16, 0, 16, 0],
              "align": "center",
              "justify": "space-between"
            },
            "sizeW": "fill",
            "sizeH": "fit",
            "children": [
              {
                "type": "text",
                "name": "Question",
                "w": 540,
                "h": 24,
                "sizeW": "fill",
                "text": "Question {n}",
                "ink": "ink",
                "typography": {
                  "role": "heading",
                  "size": 17,
                  "weight": 600
                }
              },
              {
                "type": "text",
                "name": "Icon",
                "part": "icon",
                "w": 24,
                "h": 28,
                "text": "+",
                "ink": "ink",
                "typography": {
                  "role": "body",
                  "size": 28,
                  "weight": 300,
                  "align": "center"
                }
              }
            ]
          },
          {
            "type": "stack",
            "name": "Panel",
            "part": "panel",
            "w": 640,
            "h": 64,
            "layout": {
              "direction": "column",
              "gap": 0,
              "pad": [0, 0, 20, 0]
            },
            "sizeW": "fill",
            "sizeH": "fit",
            "children": [
              {
                "type": "text",
                "name": "Answer",
                "w": 600,
                "h": 44,
                "sizeW": "fill",
                "text": "The answer to question {n}, in a sentence or two.",
                "ink": "ink",
                "typography": {
                  "role": "body",
                  "size": 15,
                  "weight": 400
                }
              }
            ]
          },
          {
            "type": "frame",
            "name": "Divider",
            "w": 640,
            "h": 1,
            "sizeW": "fill",
            "sizeH": "fixed",
            "fill": "surface"
          }
        ]
      }
    ]
  }
}

Every behaviour

Seven behaviours, every setting.

Each shown with one of the package’s Blocks. The controls are made from the checker’s own ranges, so none of them offers a value a Block cannot hold; the attribute under them is what the page carries.

Swipe, use the arrows, or the arrow keys when it has focus.

Product 1

€49

Product 2

€49

Product 3

€49

Product 4

€49

Product 5

€49

Product 6

€49

Settings Products

data-living='{"kind":"carousel","v":1,"settings":{"perView":3,"loop":false,"autoplay":false,"interval":5,"arrows":true,"dots":true,"swipe":true,"start":0,"parallax":0}}'

Roles, not colours

Lands in any design.

A Block names its colours and type by role: the accent, the surface, the ink, the heading. Pick a design: the same three Blocks take its look, still working, and only its roles change.

Our opening hours change this week. See the new times before you visit.

×

The calmest hour of my week. I leave lighter every time.

Person 1

Member since 2024

The calmest hour of my week. I leave lighter every time.

Person 2

Member since 2024

The calmest hour of my week. I leave lighter every time.

Person 3

Member since 2024

Question 1

+

The answer to question 1, in a sentence or two.

Question 2

+

The answer to question 2, in a sentence or two.

Question 3

+

The answer to question 3, in a sentence or two.

Question 4

+

The answer to question 4, in a sentence or two.

Built in, not added

Works for everyone.

The runtime owns the behaviour, so whoever draws a Block cannot leave out the keyboard or the screen reader. Use these two and watch what the page gives a screen reader.

Picture 1

A line about this picture.

Picture 2

A line about this picture.

Picture 3

A line about this picture.

Section 1

+

What a buyer should know about section 1.

Section 2

+

What a buyer should know about section 2.

Section 3

+

What a buyer should know about section 3.

Section 4

+

What a buyer should know about section 4.

Safe to share

Data, never code.

What a Block does comes from a fixed, reviewed set of behaviours, so anyone’s Block is safe to run. The checker below is the package’s own: it refuses a setting out of range, a missing part, or a field the format does not have, and says why.

Checking…

    Want to add a Block? How to contribute one.

    Made with LivingBlocks

    Running on real pages.

    Install

    On your page in a minute.

    1. Add the runtime

    npm install livingblocks

    Or as a plain script, then start it on the page:

    <script src="https://cdn.jsdelivr.net/npm/livingblocks@0.4/dist/livingblocks.min.js"></script>
    <script>LivingBlocks.start(document.body)</script>

    2. Mark the parts

    The Block’s own element carries its settings; the elements its behaviour needs carry their part:

    <section data-living='{"kind": "accordion", "v": 1, "settings": {"single": true, "start": 0}}'>
      <div data-living-part="item">
        <button data-living-part="header">Do you ship abroad?</button>
        <div data-living-part="panel">Everywhere in Europe.</div>
      </div>
      <!-- …more items -->
    </section>

    3. Change it at a breakpoint

    Settings for a smaller window go in data-living-at, applied in order as the page’s CSS cascades:

    <section data-living='{"kind": "carousel", "v": 1, "settings": {"perView": 3}}'
      data-living-at='[{"query": "(max-width: 809px)", "settings": {"perView": 1}}]'>
      …
    </section>

    For a design tool, or a store of Blocks

    The ES module has every Block, the checker and the types: draw a Block in your own style, or check one someone sent you before you keep it.

    import { BLOCKS, blockById, validateBlock } from 'livingblocks';
    
    const faq = blockById('faq');          // a Block: layers, roles, parts, settings
    validateBlock(JSON.parse(submitted));  // { ok, errors: ['settings.delay: a number from 0 to 60', …] }

    Every field and its range is in the schema, and the parts each behaviour needs in the README.

    Good to know

    Before you build on it.

    • Still 0.x. The format may change before 1.0. Each Block carries its format’s version, and a reader refuses one it does not know rather than guess.
    • Reduced motion. Slides, rings and notices change at once; nothing spins or glides.
    • Keyboard and screen readers. Arrow keys, Enter, Space and Escape where each behaviour needs them; slides announced politely, sections with their state, notices read without taking the focus.
    • A notice is not a cookie banner. With remember it stays away for that visitor until its words change; it does not record consent.
    • Credits. The ring follows Codrops’ On-Scroll 3D Carousel and the cylinder their 3D Text Animation on Scroll (MIT); both rebuilt without other libraries, their notices in the package.
    • Licence. MIT, © 2026 uxspot.io. Use it in any project, commercial ones included.

    Free, and open.

    I built LivingBlocks so the components people place in uxdeck keep working on the sites they publish, then opened it, Blocks and checker included. Use it in your code, or place the same Blocks in uxdeck without writing any.