Maple.js
Maple.js is a React webcomponents based framework mixing ES6 with Custom Elements, HTML Imports and Shadow DOM. It has in-built support for SASS and JSX, including a Gulp task for vulcanizing your project.
Install / Use
/learn @Wildhoney/Maple.jsREADME
- Heroku: http://maple-app.herokuapp.com/
- npm:
npm install maple.js - Bower:
bower install maple.js
Maple is a seamless module that allows you to organise your React project in terms of webcomponents — with HTML Imports, Shadow DOM, and Custom Elements — allowing you to implement any Flux architecture you choose, and then compile with Mapleify for production.

Getting Started
:maple_leaf: Watch "Getting Started with Maple": https://vimeo.com/128387987 (Previous)
:gem: Install all dependencies and start server using
npm start.
Given the typical Flux architecture where components reside in their respective components directory, we continue that trend in Maple, where one component can register one or many custom elements – but each HTML document can only have one template element.
Within the directory my-app/components we create our component's index that will be imported — date-time.html — which will import its associated JavaScript and CSS documents:
<template>
<script type="text/jsx" src="date-time.js"></script>
<script type="text/javascript" src="../../../vendor/moment/moment.js"></script>
<link rel="stylesheet" type="text/css" href="date-time.css" />
</template>
Note: When we import the date-time.js file we use the local path, which Maple.js understands as being a part of the module – whereas our third-party module — moment.js — resides outside of the component's directory and is therefore imported into the window scope.
Within our CSS file, we can be as loose as we like, because the date-time.js component will be imported under its own shadow boundary, preventing the styles from bleeding over into other components — even components that are children of our component.
We next need to add some standard ES6 React code to our date-time.js to make it return a date and time when rendered:
export default class MyDateTime extends React.Component {
render() {
let dateTime = moment().format(this.props.format || 'YYYY-MM-DD');
return <time>{dateTime}</time>
}
}
Note: You could use the React.createElement('datetime', null, dateTime) approach as well – the System.import we use recognises when it's a JSX file and will transpile it automatically for you.
By looking at the above React component, we can immediately deduce that the eventual custom element will be called my-date-time. For those eagle-eyed individuals amongst us, you'll have noticed we use this.props.format to specify the date/time format – and this is something we'll pass into our component when adding the custom element to the DOM.
Next all we need to do is add a little CSS to our date-time.css document:
time {
color: rebeccapurple;
font-family: Arial, Tahoma, Helvetica, sans-serif;
}
And finally import the component into our main index.html document that includes the maple.js and react.js imports:
<link rel="import" type="text/html" href="my-app/components/time-date/index.html" />
Note: You may have noticed that the component's directory name is largely irrelevant – and it is, in most cases. However, there are certain circumstances where the component's directory matters – such as when registering a Worker — In this case Maple provides the component directory as this.props.path.
Once the HTML document has been imported, Maple will register our custom element and it will be then usable in our application – although don't forget that we should pass in the optional format attribute to override YYYY-MM-DD:
<my-date-time data-format="YYYY-MM-DD HH:mm"></my-date-time>
Note: In the above example we use data-format, whereas our React component expects format — you'll be glad to know that in these cases, Maple strips the data- segment from the attribute, which allows you to write perfectly valid HTML5 syntax.
Component Path
From within your React component, use the this.props.path.getRelativePath() to get the path of the current component – with this information, you can easily register Workers and other relatively stored documents:
let name = 'MyWebWorker.js',
path = `${this.props.path.getRelativePath()}/${name}`,
worker = new Worker(path);
Ignore Import
Importing a HTML file may not require Maple at all, and therefore if the imports were left to be processed by Maple this would be a waste of resources – as no components would be contained within the import. For these cases you can add the data-ignore attribute to the HTML import, and Maple will leave them unprocessed:
<link rel="import" type="text/html" href="example.html" data-ignore />
Multiple Elements
Each HTML document can have exactly one template element registering components. In cases where you want to register multiple components, you must split them into their individual HTML documents for developers to import separately. For instance, a DateTime component could yield date-time-gmt, date-time-bst, etc... Each element can have its own associated CSS documents as well. There are two approaches for this:
- Create two HTML documents:
index-gmt.htmlandindex-bst.htmland require them to be imported separately; - Create one HTML import with one
templatenode and import both JS documents with a shared CSS document:
<template>
<script type="text/javascript" src="datetime-gmt.js"></script>
<script type="text/javascript" src="datetime-bst.js"></script>
<link rel="stylesheet" type="text/css" href="shared.css" />
</template>
Choosing between the two approaches should be evident – if you want to apply custom CSS documents to each component individually — datetime-gmt.css to one, and datetime-bst.css to the other — then you should have two HTML documents. Otherwise if the two are directly related, and share the same CSS and JS documents, then they can be kept together in one HTML document.
JSX Compilation
In development environments it is often useful to compile JSX documents — Maple supports JSX compilation. All you have to do is import JSX the usual JSX way using the text/jsx type:
<template>
<script type="text/jsx" src="my-jsx-document.js"></script>
</template>
Note: When using Mapleify to render your app – Mapleify merely changes the type of your script elements from text/jsx to text/javascript and changes the extensions from .jsx to .js (pre v1.2.0 when JSX files were included with JSX extensions) – it's left entirely up to the developer to write their Gulp/Grunt scripts to convert their JSX — and SASS — documents prior to Mapleify compilation.
Also Note: Since the release of v1.2.0 JSX files must have a JS extension – also JSX files will import just fine using a text/javascript type, too.
Nested Shadow Boundaries
As Maple uses Custom Elements to create the components, it's straightforward to have components within components – you only need to place your Custom Element node into your React component:
render() {
return <li><date-time data-unix={model.date}></date-time></li>
}
SASS Transpiling
:maple_leaf: Watch "SASS to CSS": https://vimeo.com/128343626
In a development environment Maple supports transpiling SASS documents to CSS documents – for production you should use your build tool to transpile SASS to CSS documents.
Maple uses Sass.js and can be installed separately:
bower install sass.js -D
Once you have included sass.js all documents that are included with the type text/scss will be automatically transpiled for you to CSS before being appended to the shadow boundary:
<link type="text/scss" href="default.scss" />
Resolved Components (FOUC)
:maple_leaf: Watch "Preventing FOUC": https://vimeo.com/128343604
Maple uses the same mechanism as Polymer when it comes to preventing FOUC. Place the unresolved attribute on each element, and then once they're upgraded by Maple, the unresolved attribute will be replaced with the resolved attribute:
<date-time unresolved></date-time>
With the following styles the date-time element will fade in gradually once upgraded:
date-time {
opacity: 0;
display: block;
transition: opacity 3s;
}
date-time[resolved] {
opacity: 1;
}
Mutation Observer
:maple_leaf: Watch "Mutation Observer": https://vimeo.com/128588608
Maple uses the MutationObserver to listen for changes to the `document
Related Skills
openhue
342.5kControl Philips Hue lights and scenes via the OpenHue CLI.
sag
342.5kElevenLabs text-to-speech with mac-style say UX.
weather
342.5kGet current weather and forecasts via wttr.in or Open-Meteo
tweakcc
1.5kCustomize Claude Code's system prompts, create custom toolsets, input pattern highlighters, themes/thinking verbs/spinners, customize input box & user message styling, support AGENTS.md, unlock private/unreleased features, and much more. Supports both native/npm installs on all platforms.
