npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

magritte

v0.1.1

Published

A fast and simple reactive view library for the browser

Downloads

10

Readme

Magritte

A tiny reactive view library for the browser with a functional interface and a DOM abstraction that allows incremental rendering. Key features include API simplicity, functional composition, store immutability, and very little boilerplate.

Magritte has a built in store model that provides an immutable state and a model dispatcher. The store dispatcher has a type-check mechanism that prevents runtime changes to the ‘kind of content’ in the state. Components that utilise functional composition are resolved using the store which means your state and model are available in every component.

Features

  • fast: a virtual DOM abstraction with incremental updates
  • safe: an immutable one-directional data store that prevents run-time changes to its structure
  • linguistic: supports JSONML (default), hyperscript, and JSX template syntax
  • flexible: attribute middleware and full SVG support including xlink-attributes
  • expressive: A functional interface that favours composition
  • portable: No build pipeline required
  • tiny: a mere 5Kb minified (2Kb gzipped)

Roadmap...

  • A router,
  • Component lifecycle methods,
  • Isomorphic rendering,
  • Unit tests,
  • Performance tests,
  • Full documentation.

Getting Started

npm install magritte or download bundle/magritte.js to use it straight away. Magritte including its template syntax is plain JavaScript and can be used without any build pipeline.

Demo on JSFiddle

Beware that Magritte should not be used in production at this time and is prone to changes in its API.

Hello World!

You’ll need a root element,

<div id="root"></div>

a component,

const events = {
	onclick({ model }) {
		model.name('Jane')
	},
}

const Title = ({ state, model }) => 
	['h1', events, `Hello ${state.name}!`]

a store model with the initial state,

const storeModel = { name: 'World' }

and some composition...

// create a component with a DOM selector and your root components
const component = magritte('#root', Title) 

// and render the component using the storeModel
component(storeModel) 

Components

A component can either be:

  • A function: functions are resolved using the store as its arguments,
  • A plain attributes-Object: { className: 'hello' },
  • A content string or number: 'abc' or 123,
  • An JSONML template as following: ['tagName', <child component>, <child component>, ...].

In addition null, true, or false are valid as well:

  • Return null to remove an element from the DOM.
  • Return true to force a re-render of the component using the augmented virtual DOM.
  • Return false to skip rendering for the component and leave it as is.
  • Return undefined to skip rendering for the component and leave it as is.

Store

The store is an object that is passed to every component function, its properties are state and model.

For a more detailed explanation and example see ./example/store/.

state

The state is a frozen object (no property reassignment) that keeps track of the application state. Supported data types are the same as those of JSON; null, a string, a number, an Array, or a child Object. The state is a reflection of the storeModel that was initially passed at component initialisation, this model should provide the data structure for the entire lifecycle of the application (see ./example/model).

By defining the model beforehand the developer is sure to abide to an existing data structure (no runtime changes) which at the same time has been documented as well.

model

The model has a structure derived from the storeModel that was passed to the component at its first render and will be passed to every function in a component, its update-methods accept either:

  • A function: functions are resolved using the current value in the state and the entire state Object as its arguments, its return value is used to update the store and DOM if the state has changed.
  • An Array: this will only update the state if its value was initially an Array, a warning will be logged otherwise.
  • A string or number: this will only update the state if its value was initially a string or number, a warning will be logged otherwise.
  • A boolean: this will only update the state if its value was initially a boolean, a warning will be logged otherwise.
  • undefined: there will be no change, the component render method will not be initiated.
  • null: this renders the component using the state that it was initially given (not implemented yet).

API

magritte

Magritte is a function that accepts any number of components, the first argument however is expected to be a document query selector. After declaring the component it can be rendered using a storeModel that acts as the initial state, and the entire data structure of the component.

const render = magritte('#root', One, Two, Three)

const storeModel = { greeting: "Hello Operator!" }

component(storeModel)

#compose

Compose is a method that allows you to predefine element structures, this may be helpful to define global structural elements:

// define an element structure
const pageSection = magritte.compose('page', { className: 'section' })

// ...and use it anywhere you like.
pageSection('This is a page section')

You can override the initial attributes by passing an alternative to the composed method:

// set the input type to "text" by default
const input = magritte.compose('input', { type: 'text' })

// ...and override it if need be
input({ type: 'email', ... }) 

#element

The element method is a wrapper for the JSONML interface and reminiscent of hyperscript, it can be used as an alternative to the default syntax. It was designed as a foundation for JSX-compability (under consideration).

The following element...

const Header = ({ state }) => ['header', { className: 'page' },
	['h1', state.title],
]

... can also be written like this:

const { element } = magritte

const Header = ({ state }) => element('header', { className: 'page' },
	element('h1', state.title),
)

These two snippets above have an identical outcome.

#handleAttributes

With handleAttributes you can define middleware that is responsible for setting attributes to an element. By default aria, data, viewBox, and xlink-attributes use a bespoke attribute handler to ensure compatibility with the DOM-API. By default the attribute value is set directly as the node property value, therefor a class attribute must be defined using the Node.className property name.

The default bespoke methods are located at ./source/middleware/attributeHandlers.

#route

Not implemented yet, will be used to define routed components.

#jsx

Magritte can now be used with JSX (experimental), to do this use a Babel JSX plugin and set its pragma option to 'magritte.jsx'.

Component child functions are no longer resolved using the store automatically, you can use jsx-props instead: <Component item={item}/> which passes an Object with an item property to a child component as usual.