Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/Wildhoney/Standalone
Create framework agnostic components that are truly reusable and interoperable with all the benefits of the React ecosystem – using the HTML5 custom elements API to extend HTML's vocabulary.
https://github.com/Wildhoney/Standalone
components custom-elements react reactjs webcomponents
Last synced: about 2 months ago
JSON representation
Create framework agnostic components that are truly reusable and interoperable with all the benefits of the React ecosystem – using the HTML5 custom elements API to extend HTML's vocabulary.
- Host: GitHub
- URL: https://github.com/Wildhoney/Standalone
- Owner: Wildhoney
- License: mit
- Created: 2016-04-06T16:05:52.000Z (about 8 years ago)
- Default Branch: master
- Last Pushed: 2016-09-26T14:02:11.000Z (almost 8 years ago)
- Last Synced: 2024-05-06T21:42:42.683Z (about 2 months ago)
- Topics: components, custom-elements, react, reactjs, webcomponents
- Language: JavaScript
- Homepage: http://react-standalone.herokuapp.com/
- Size: 6.49 MB
- Stars: 206
- Watchers: 11
- Forks: 10
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Lists
- awesome-webcomponents - Standalone
- awesome-custom-elements - Standalone
README
![React Standalone](media/logo.png)
> Create framework agnostic components that are truly reusable and interoperable with all the benefits of the React ecosystem – using the HTML5 [custom elements API](https://www.w3.org/TR/custom-elements/) to extend HTML's vocabulary.
![Travis](http://img.shields.io/travis/Wildhoney/Standalone.svg?style=flat-square)
![npm](http://img.shields.io/npm/v/react-standalone.svg?style=flat-square)
![License MIT](http://img.shields.io/badge/license-mit-lightgrey.svg?style=flat-square)* **npm:** `npm install react-standalone --save`
## Table of Contents
* [Getting Started](#getting-started)
* [Handling Props](#handling-props)
* [Specifying a Schema](#specifying-a-schema)
* [Component Events](#component-events)
* [Passing JSON Structure](#passing-json-structure)
* [Element Methods](#element-methods)
* [Extending Elements](#extending-elements)
* [Browser Support](#browser-support)
---## Getting Started
Take a look at the [`mars-weather` component](example/packages/mars-weather) for an idea on how to structure your reusable component – however essentially a *component* consists of a tag name — such as `mars-weather`, the React `component` and an [optional schema](#specifying-a-schema) using [`osom`](https://github.com/Kikobeats/osom).
```javascript
import { createModule } from 'standalone';
import schema from './schema';
import component from './component';export default createModule('mars-weather', { schema, component });
```
Once you have created your package, a custom element will be created with the supplied `tagName` which can be embedded into the DOM – all of the React lifecycle methods will be invoked, such as `componentWillUnmount` when the element has been removed from the DOM.
```html
```
As the `mars-weather` component is an entirely custom element, it can be embedded in **any** JavaScript framework — Angular, Vue, React, Cycle, Ember, [Vanilla](http://vanilla-js.com/), etc...
**Bonus:** Use [Keo with shadow boundaries](https://github.com/Wildhoney/Keo/blob/master/docs/SHADOW_DOM.md) for a true [Polymer-esque](https://www.polymer-project.org/1.0/) feel.
## Handling Props
By specifying attributes on the custom element, the values of the attributes are passed into your component as props – any changes to the `state` will be handled internally to your component, whereas any changes to your element's attributes will cause a re-render with the updated `props`.
In the `mars-weather` example, we have setup the `getDefaultProps` method to return the default props, however users can override the `unit` prop by passing in a [`data` attribute](http://html5doctor.com/html5-custom-data-attributes/) named `data-unit`.
```html
```
In the above case, the `data-unit` attribute will be transformed to `unit` — as `Standalone` strips away any `data-` prefixes — and then re-renders your component, allowing you to access the attribute as `this.props.unit`.
### Specifying a Schema
As **all** HTML attributes are `string`s, `Standalone` allows you to specify a schema for your component, which will transform `string` attributes into the data type you expect using [`osom`](https://github.com/Kikobeats/osom).
```javascript
export default {
unit: {
type: String,
default: 'F'
}
};
```Once you have configured the schema to use for your component, you can happily setup the usual [React `propTypes`](https://facebook.github.io/react/docs/reusable-components.html) specifying the data type you're expecting to be passed through.
## Component Events
Using [Custom Events](https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events) you can easily set-up a communication channel between your components and the outside world.
```javascript
// Instantiate `CustomEvent` and then specify the name of the event, followed
// by the payload which will be passed to your listener function.
const event = new CustomEvent('migrate-planets', {
bubbles: true,
detail: {
planet: 'Saturn'
}
});findDOMNode(this).dispatchEvent(event);
```It's crucial that you emit the event as `bubbles: true` otherwise the event would simply halt at the `findDOMNode(this)` node rather than bubbling up to the `mars-weather` node — unless you dispatch the event on the `mars-weather` node by using `findDOMNode(this).parentNode`.
Within your component you emit the event — `CustomEvent` — using `dispatchEvent` and then bind your custom element — such as `mars-weather` — using `addEventListener` from the outside.
```javascript
const node = document.querySelector('mars-weather');node.addEventListener('migrate-planets', event => {
// Update the `data-planet` attribute to reflect the newly migrated planet
// which will cause the component to re-render with the update prop.
node.setAttribute('data-planet', event.detail.planet);});
```### Passing JSON Structure
As invoking `setAttribute` on your component causes React to re-render your component, it may be useful to supply a JSON payload to your component instead — especially if you're defining a multitude of attributes; this also helps with performance as you would only need one `setAttribute` to update many props and re-render.
By defining a schema you can specify an attribute that will be parsed as JSON.
```javascript
export default {
payload: {
type: JSON.parse
}
}
```Attaching a JSON string to your element's `data-payload` attribute will cause it to be parsed into an object using `JSON.parse`, and passed to your React component as `this.props.payload` which can be defined in the `propTypes` using `PropTypes.shape`.
## Element Methods
All `Standalone` components extend `HTMLElement.prototype` and allow for adding custom functions to the element — which you can invoke once you have a reference to the associated element. Take a look at [`mars-weather`'s methods](https://github.com/Wildhoney/Standalone/blob/master/example/packages/mars-weather/methods.js) for an example.
```javascript
const getWeather = function() {
const weather = this.component.state.weather.atmoOpacity.toLowerCase();
return `The current weather on Mars is ${weather}!`;
};// ...
document.querySelector('mars-weather').getWeather();
```When a component has been appended to the DOM it will update its `HTMLElement` prototype to assign the rendered component to `getPrototypeOf(this).component` — this conveniently allows you to access the `props` and `state`, and invoke functions internal to the React component.
It's worth noting that `this.component` will **only** be available once the component has been appended to the DOM.
## Extending Elements
With the Custom Elements API it is possible to extend existing elements – using the `is` attribute to specialise. `Standalone` allows you to extend elements by passing the element to extend.
```javascript
// Creates a `mars-weather` element.
export default createModule('mars-weather', { schema, methods, component });// Creates a `input[is="mars-weather"]` element.
export default createModule('input/mars-weather', { schema, methods, component });
```It's worth noting that when you extend a known element, your element will extend its prototype – in the case above the `mars-weather` element will extend `input` and its `HTMLInputElement` prototype.
## Browser Support
* Chrome >= v33
* Opera >= v20
* *IE >= 11
* *Safari >= 7
* *Firefox_\* Requires the excellent [webcomponents-lite.js](https://github.com/WebComponents/webcomponentsjs) polyfill (13K gzipped)_
[![forthebadge](http://forthebadge.com/images/badges/built-with-love.svg)](http://forthebadge.com)