Skip to content

Latest commit

 

History

History
109 lines (77 loc) · 5.06 KB

SHADOW_DOM.md

File metadata and controls

109 lines (77 loc) · 5.06 KB

Keo

"Keo" is the Vietnamese translation for glue.
Plain functions for a more functional Deku approach to creating stateless React components, with functional goodies such as compose, memoize, etc... for free.

Shadow DOM

As Shadow DOM is part of the webcomponents suite, there is a useful polyfill which you can use for wider browser support — please refer to their documentation for a list of supported browsers.

Note: Works in React >=15.0.2see issue and associated PR.


Shadow DOM

By using function composition in Keo, you are able to add additional behaviour to your functions by using compose or pipe – in this case we are using the bundled shadow function to enable Shadow DOM in React.

Getting Started

In order to use Shadow DOM you need to compose your render function, which means importing compose — or pipe — from Ramda, along with shadow from Keo and then composing your render function.

import { compose } from 'ramda';
import { stitch, shadow } from 'keo';

// ...

const render = compose(shadow(), ({ props }) => {
    return (
        <section className="greeting">
            <h1>Hello ${props.name}</h1>
        </section>
    );
});

Once you have the composition setup with shadow you should find your DOM rendering with a shadow root. Keo takes your component's root element and appends that to the DOM tree; it then creates a shadow root and renders your component's children inside.

Note: If you have only one child then your component will be rendered directly beneath the shadow root, otherwise due to a well-known React limitation, a span will be the immediate descendent of the shadow root, and your component will be rendered within that span.

You should see the following when inspecting the DOM:

<section class="greeting resolved">
    #shadow-root (open)
        <h1>Hello Adam</h1>
</section>

Any event listeners and other props on your root section element will be transferred across and therefore work as you would expect.

CSS Documents

You may have noticed that when composing your render function that you're invoking shadow instead of simply passing it in – that is because the shadow function is curried and accepts two arguments: the first being a string or an array of stylesheets, and the second being the result of your render function which compose — or pipe — will handle for you.

Therefore to pass in stylesheets to be used with your component, simply pass in a path to your CSS document(s):

const render = compose(shadow('/css/greeting.css'), ({ props }) => {
    return (
        <section className="greeting">
            <h1>Hello ${props.name}</h1>
        </section>
    );
});

You should now see the following DOM structure with the style element applied next to your component:

<section class="greeting resolving">
    #shadow-root (open)
        <h1>Hello Adam</h1>
        <style type="text/css" />
</section>

FOUC

As the stylesheets are downloaded asynchronously, there is a small period of time where your component will be rendered without the styles applied — this is known as a flash of unstyled content (FOUC). For these purposes it may be useful to hide your component until the styles have been applied — that is the reason for Keo appending resolved or resolving to your component's root element:

<section class="greeting resolving">
    #shadow-root (open)
        <h1>Hello Adam</h1>
        <style type="text/css" />
</section>

When the component has the class name resolving then it may be wise to hide the element, or at least let users know the component hasn't yet finished rendering. However once the class name is resolved then the component should have all the styles it needs to be displayed beautifully.

Pipe

It's been mentioned that you could also use pipe to place the shadow function at the end for readability purposes — whichever you choose is entirely up to you — but don't forget to be consistent across components!

import { pipe } from 'ramda';
import { stitch, shadow } from 'keo';

// ...

const render = pipe(({ props }) => {
    return (
        <section>
            <h1>Hello ${props.name}</h1>
        </section>
    );
}, shadow(['/css/greeting.css', '/css/headers.css']));