LiteralJS
~1kb JavaScript library for building user interfaces.
$ microbundle
Build output to build:
1.51 kB: index.js
1.53 kB: index.m.js
1.56 kB: index.umd.js
- Small: Only around 1kb in size.
- Fast: Current and previous vDOM are diffed against each other for performant updates and rendering.
- Virtual DOM: Diffing occurs on state update for more efficient DOM updates.
- Flexible Syntax: Freedom to use JSX, Hyperscript, or Object syntax.
- Lifecycle Methods: All DOM elements have the ability to trigger
mounted
, updated, and
unmounted` lifecycle functions. - One Global Store: One source of truth which makes other state management libraries less of a need.
Documentation Index
API Functions
The easiest way of getting started is by cloning the LiteralJS starter application located here:
Once you clone the project, you cd
to the directory and run the following commands:
$ npm install
$ npm run dev
$ yarn
$ yarn dev
This command is setup to launch a browser window and you should see a landing page. The project is also partially setup to deploy to Netlify if you want. Just make sure to use the build-netlify
command in the Netlify dashboard and set the deploy folder to dist
.
$ npm install literaljs
$ yarn add literaljs
Import
const Literal = require('literaljs');
import Literal from 'literaljs';
import { component, render, h } from 'literaljs';
ES6 Examples
You can use 3 types of markup in the render!
JSX
const Foo = component({
render: ({ state, getState, setState }) => (
<div class='container'>
This is the Count: {state.count}
<button
events={{
type: 'click',
action: () => setState({ count: getState().count + 1 })
}}>
Click Me!
</button>
</div>
)
});
render(foo, 'app', { count: 0 });
Hyper Script
const Foo = component({
render: ({ state, getState, setState }) =>
h('div', {
class: 'container',
text: `This is the Count: ${state.count}`
}, [
h('button', {
events: {
type: 'click',
action: () => setState({ count: getState().count + 1 })
}
})
]
);
});
render(foo, 'app', { count: 0 });
Objects
const Foo = component({
render: ({ state, getState, setState }) => ({
element: 'div',
class: 'container',
text: `This is the Count: ${state.count}`,
children: [
{
element: 'button',
text: 'Click Me!',
events: {
type: 'click',
action: () => setState({ count: getState().count + 1 })
}
}
]
})
});
render(foo, 'app', { count: 0 });
component
The component
function accepts objects with the following keys:
The props
of a component
is an object which can be passed with anything that is normally valid in a JavaScript Object. This can include any data or functions.
The only component that can not recieve props
is the root component that is passed to the Literal.render
function.
Example:
const Bar = component({
render: ({ props }) => (
<p>Total: {props.total}</p>
)
});
const Foo = component({
render: () => (
<div>{Bar({ total: 9 })}</div>
)
});
The methods
key of a component
will accept a function which returns an object of other functions. Within the methods
, you also have access to a component
s getState
and setState
functions which can be used accordingly. You also, have access to created methods directly within the render
function.
getState
is a function which is accessible as a property of the methods
function.
Using the getState
function will pull the latest state objecty of your application. Once used, the specific state keys are accessible via dot notation.
setState
is a function which is accessible as a property of the methods
function.
Using the setState
function will cause the application state to update and diffing to occur.
Example:
component({
methods: ({ getState, setState }) => ({
increase: () => setState({ count: getState().count + 1 })
}),
render: ({ state, getState, setState, methods: { increase }}) => (
<button
events={{
type: 'click',
action: () => increase()
}}
>
Current Count: {state.count}
</button>
)
});
The render
key of a component
accepts a function that returns an JavaScript Object.
JSX in LiteralJS has some differentiation when it comes to other implementations like JSX in React.
The biggest differentiator in syntax from React JSX is that the class
attribute is acceptable on JSX elements and events
are passed as either an Array or Objects or a single Object.
Event Objects need a type
and action
which are explained here.
Anything can be considered acceptable as attributes and any keys that work with LiteralJS Object Markup Syntax also work in LiteralJS JSX markup.
Example Of Single Event:
component({
methods: ({ getState, setState }) => ({
increase: () => setState({ count: getState().count + 1 })
}),
render: ({ state, getState, setState, methods: { increase }}) => (
<button
events={{
type: 'click',
action: () => increase()
}}
>
Current Count: {state.count}
</button>
)
});
Example Of Multiple Events:
component({
methods: ({ getState, setState }) => ({
increase: () => setState({ count: getState().count + 1 })
}),
render: ({ state, getState, setState, methods: { increase }}) => (
<button
events={[
{
type: 'mounted',
action: () => console.log('Button Mounted')
},
{
type: 'click',
action: () => increase()
}
]}
>
Current Count: {state.count}
</button>
)
});
Object Markup is currently written with Objects with the following specified keys or strings:
* = Required Key
element Key
The element
key in the render
function markup is the HTML node tag name as a String
. For example, an element
with the value
The element
key is required when generating a new DOM node.
Example:
component({
render: () => ({
element: 'div',
})
});
text Key
The text
key in the render
function markup accepts a String an will generate a text inside the element.
Example:
component({
render: () => ({
element: 'div',
text: 'Hello World!'
})
});
You can also include regular strings as children to create text nodes.
Example:
component({
render: () => ({
element: 'div',
children: ['Hello World!']
})
});
class Key
The class
key in the render
function markup is the HTML node class name as a String
.
Example:
component({
render: () => ({
element: 'div',
class: 'title'
})
});
id Key
The id
key in the render
function markup is the HTML node class name as a String
.
Example:
component({
render: () => ({
element: 'div',
id: '2'
})
});
children Key
The children
key in the render
function markup represet the childNodes
of a given element
or DOM Node. This key only accepts an Array of Objects or Strings. Each Object or in this Array can be another Object that represents a new DOM Node. You can also use Strings to represet Text nodes.
Example:
component({
render: () => ({
element: 'div',
children: [
'Count: ',
{
element: 'span'
text: '0'
}
]
})
});
The events
key in the render
function markup accepts either an Array of events or a single event Object.
An event object has two keys:
type
(Event Name)action
(Function To Trigger)
Example:
component({
render: () => ({
element: 'button',
text: 'Click Me!',
events: [
{
type: 'click'
action: () => console.log('Hello World!')
}
]
})
});
component({
render: () => ({
element: 'button',
text: 'Click Me!',
events: {
type: 'click'
action: () => console.log('Hello World!')
}
})
});
Besides the common event handlers like click
, there are two lifecycle events that LiteralJS
includes that can be attached to any DOM node.
To do so, just name the type
value unmounted
, updated
, or mounted
to trigger functions when a DOM node is first placed in the DOM or removed from the DOM.
Example:
Example:
component({
render: () => ({
element: 'div',
text: 'I have a life!',
events: [
{
type: 'mounted'
action: () => console.log('I\'m on the page!')
},
{
type: 'updated'
action: () => console.log('I\'m updated!')
},
{
type: 'unmounted'
action: () => console.log('I\'m off the page!')
}
]
})
});
Other Keys Not Listed
Other keys are also accepted in a DOM object, such as data
and other custom keys.
Properties
Within the render
function of a component, you have access to other functions and objects:
state
The state
property is an Object of the current state and should only be used within markup and not functions or events.
getState
The getState
function of the component
s render
method will allow you to access the global store of your application within functions and events.
setState
The setState
function of the component
s render
method accepts an object which will allow you to set new values for particular pieces of state in the global store
props
The props
object of the component
s render method can contain any number of data types and functions. The only
componentthat cannot contain
propsis the root
componentthat is passed to the
Literal.render` method.
methods
The methods
object allow you to access other functions defined directly in the component
. You can use this as a way to organize other pieces of logic and keep the render
function much cleaner.
render
The Literal.render
function is responsible for parsing the AST that is provided with component
s, injecting the generated markup into the specific DOM node, diffing any new changes based on state, and setting the default application state.
The Literal.render
function can accept 3 arguments, one of which is optional.
- The root component.
- The String
id
of the DOM node to inject generated markup with. - (Optional) The default state as an Object
Example:
Literal.render(component, 'app', { count: 0 });
render(component, 'app');
h
The Literal.h
function will generate specific LiteralJS Object Syntax.
If you want to use JSX, you can import the Literal.h
function and install the JSX transform plugin and add the pragma option to your .babelrc
file.
In .babelrc
:
{
"plugins": [["transform-react-jsx", { "pragma": "h" }]]
}
Some text editors and linters might also require the following at the top of the file to recognize that the file is using JSX: