xmetal

React-inspired XML/HTML component library for Javascript

Usage no npm install needed!

<script type="module">
  import xmetal from 'https://cdn.skypack.dev/xmetal';
</script>

README

:metal: xMetal :metal:

XML/HTML functional component library for Javascript

Designed to work with any XML-based markup and can run both in the browser and on Node.

xMetal is heavily influenced by React and tries to remove a lot of the tooling overhead. It allows you to get up and running quickly with minimal changes on your end.

Why another view library?

  • Pure functional Javascript
  • Scalable abstraction
  • No tooling required
  • No dependencies
  • No JSX, while still keeping markup easy to write
  • Works with any XML markup, not just HTML

HTML helper

HTML is probably the most popular XML-based language. Therefore, baked into xMetal is a helper with a list of primitive html components. To use those primitives, simply run

const {h1, h2, div} = require('./Html')

Behind the scenes, the HTML helpers creates components using the createComponent function. You can create your own primitives based on the XML language in your domain.

const { createComponent } = require('Component')
const div = createComponent('div')

Writing a component

Let's create a component called MyComponent that is represented by a pure function that returns another component.

// MyComponent.js
const {div} = require('./Html')
module.exports = () => div({class: 'saada'})

Components are composable and can be combined together to form larger components. Let's add more components to our previous example.

// MyComponent.js
const {h1, h2, div} = require('./Html')

module.exports = () => 
  div({class: 'saada'}, [
    h1({}, 'Text1'),
    div({}, [
      h2({}, 'Text2')
    ])
  ])

You can render your component by calling

const {render} = require('Component')
const MyComponent = require('./MyComponent')

const output = render(MyComponent())
console.log(output)

output

<div class="saada">
  <h1>Text1</h1>
  <div>
    <h2>Text2</h2>
  </div>
</div>

Props

Let's add some props to make the text customizable

// MyComponent.js
const {h1, h2, div} = require('./Html')

module.exports = (props) => 
  div({class: props.class}, [
    h1({}, props.header),
    div({}, [
      h2({}, props.subHeader)
    ])
  ])

Let's call render

const {render} = require('Component')
const MyComponent = require('./MyComponent')

const output = render(MyComponent({
  class: 'red', 
  text1: 'Header', 
  text2: 'Subheader'
}))
console.log(output)

output

<div class="red">
  <h1>Header</h1>
  <div>
    <h2>Subheader</h2>
  </div>
</div>

Children

Along with props, components take a second parameter of children which can be an array or a string. Strings are output directly inside the element by default and arrays are treated as child components. Let's say we want to pass an array of users and display a list of users.

// User.js
module.exports = (props) => li({}, `${props.firstname} ${props.lastname}`)

// UserList.js
const {ul} = require('./Html')
module.exports = (props = {}, children = []) => ul(props, children)

// index.js
const users = [
  { firstname: 'Gandalf', lastname: 'The Grey' },
  { firstname: 'Michael', lastname: 'Jackson' }
]

const {render} = require('Component')
const UserList = require('./UserList')
const User = require('./User')

const output = render(UserList({}, users.map((user) => User)))
console.log(output)

output

<ul>
  <li>Gandalf The Grey</li>
  <li>Michael Jackson</li>
</ul>

Add Logic

Now let's say we wanted to add some logic to the previous example. We can do so by adding more functions in our component file. Let's say we wanted to lowercase user first names and uppercase user last names.

// User.js
const formatUserName = (user) => {
  user.firstname = user.firstname.toLowerCase()
  user.lastname = user.lastname.toUpperCase()
}

module.exports = (props) => {
  let user = formatUserName(props)
  return li({}, `${user.firstname} ${user.lastname}`)
}

TODO:

  • Examples with CSS
  • Examples with browser routing
  • Examples with async calls
  • DOM Examples
  • DOM diffing
  • Cross browser support