Custom elements
NOTE: custom elements are still under active development. The architecture will be changing in the near future to add more flexibility.
The Hyperview can be extended with custom elements that can be referenced and configured via HXML. Custom elements allow you to create rich, interactive client-side components, while controlling the layout of these elements from the backend server.
Creating custom elements
Custom Hyperview elements are backed by a React Native component. Any React Native component can be a custom element. There are only two required static class properties for custom components:
| Property | Type | Required | Description |
|---|---|---|---|
| namespaceURI | string | Yes | The XML namespace for the element |
| localName | string | Yes | The local tag name (within the XML namespace) for the element |
| supportsHyperRef | boolean | No | Set to true to enable behavior attributes (href, action, <behavior> children) on the custom element's root tag. Defaults to false. See Behavior support below. |
| getFormInputValues | function | No | A function with the signature (element): Array<[string, string]>. Add this if your custom element contains data that should be serialized into a parent form. The array return value allows for the custom element to serialize multiple name/value pairs. Most commonly, your element would return one name/value pair, like [["first_name", "Alice"]]. You can also return multiple values for one name, like [["choice", "1"], ["choice", "2"]]. Or multiple values with multiple names, like [["state", "CA"], ["country", "USA"]] |
When rendering the component, Hyperview will pass screen context to render() as props. The component is free to use these props if it wants to render sub-children:
| Prop | Type | Description |
|---|---|---|
| element | xmldom Element object | The element DOM object from the HXML |
| stylesheets | object | RN Stylesheets defined in the screen's HXML |
| onUpdates | function | Callback that triggers a behavior |
For example, if we wanted to expose a map element within Hyperview, we can wrap MapView from react-native-maps in a class that adds the two required properties:
import Hyperview from 'hyperview';
import MapView from 'react-native-maps';
export default class HyperviewMap extends PureComponent<Props> {
static namespaceURI = 'https://instawork.com/hyperview-map';
static localName = 'map';
render() {
// Parses the HXML elements attributes.
// Returns styles and custom props.
const props = Hyperview.createProps(
this.props.element,
this.props.stylesheets,
this.props.options,
);
// Render any HXML sub-elements using Hyperview.
const children = Hyperview.renderChildren(
this.props.element,
this.props.stylesheets,
this.props.onUpdate,
this.props.options,
);
const region = {
latitude: parseFloat(props.latitude),
longitude: parseFloat(props.longitude),
latitudeDelta: parseFloat(props['latitude-delta']),
longitudeDelta: parseFloat(props['longitude-delta']),
};
return (
<MapView {...props} region={region} liteMode>
{children}
</MapView>
);
}
}
Behavior support
By default, when a custom element has behavior attributes set, or nested behaviors as immediate children, the attributes are not processed (e.g. <my-ns:my-element href="/some/path" /> or <my-ns:my-element><behavior href="/some/path" /></my-ns:my-element>)
There are two ways to support behaviors on a custom element:
Option A — Opt the component in with supportsHyperRef
Set the static property supportsHyperRef = true on the component. When behavior attributes are present, Hyperview will wrap the element with HyperRef before rendering — the same mechanism used by built-in elements like <view> and <text>.
MyComponent.namespaceURI = 'https://example.com/my-ns';
MyComponent.localName = 'my-element';
MyComponent.supportsHyperRef = true;
<my-ns:my-element
xmlns:my-ns="https://example.com/my-ns"
href="/next-screen"
action="push"
/>
Option B — Place behaviors on a wrapping standard element in HXML
No component code change is needed. Wrap the custom element in a standard <view> and put the behavior attributes there instead:
<view href="/next-screen" action="push">
<my-ns:my-element xmlns:my-ns="https://example.com/my-ns" />
</view>
Note: behaviors on child elements rendered by
renderChildrenare always processed correctly regardless ofsupportsHyperRef, because each child passes throughhv-elementindependently.
Configuring the client
Once you've defined a RN component with the required static properties, you can pass the class to the Hyperview component. This will register the component as an element available to be used during rendering of the screen. Custom components are passed in using the components prop, which takes an array of component classes.
function Screen({ url }) {
return (
<Hyperview entrypointUrl={url} fetch={fetch} components={[HyperviewMap]} />
);
}
Using in HXML
Now that the custom element is registered with the Hyperview component, you can reference it in HXML using the provided namespace and tag name:
<view xmlns:maps="https://instawork.com/hyperview-map">
<maps:map
latitude="37.781229"
longitude="-122.393232"
latitude-delta="0.0922"
longitude-delta="0.0421"
/>
</view>
This would display a map with the given coordinates and zoom level on a Hyperview screen.