Framework agnostic UI kit example based on Web Components
$ npm install
$ npm start
$ npm run build
- generates static markup and builds for production
- Autonomous Custom Elements
- NO Shadow DOM but Slots approach is implemented
- Preact as a reactive template engine
- HTM - temporal dependency; should be replaced with corresponding TS/Babel config
Utils:
src/index.js
- entry point with hydrationReactDOM.hydrate(<App />, rootElement);
src/ssr.js
- script which generates static markupReactDOMServer.renderToString(React.createElement(App))
src/utils/define.js
- helper to simplify declaration of custom elements- embeds Preact into custom element life cycle as a template engine
- implements Slots approach
src/utils/reactWrapper.js
- Web Component => React Component adaptersrc/utils/html.js
- wrapper for temporal dependency HTM
Web Components:
src/Button
-rshb-button
src/Checkbox
-rshb-checkbox
src/Dropdown
-rshb-dropdown
src/Input
-rshb-input
Form example: App.js
import { define } from "../utils/define";
import { html } from "../utils/html";
import "./Checkbox.css";
export const Checkbox = define(
class extends HTMLElement {
// Custom element tag name
static tag = "rshb-checkbox";
/**
* Custom element attributes definition
*
* type AttrName = string;
* type AttrConverter<PropType = any> =(attrValue: string) => PropType;
* type AttrsDefinition = Record<AttrName, AttrConverter>;
*/
static props = {
id: String,
name: String,
checked: Boolean,
disabled: Boolean
};
/**
* Custom element slots definition
*
* type SlotName = string;
* type SlotCSSSelector = string;
* type SlotsDefinition = Record<SlotName, SlotCSSSelector>;
*/
static slots = {
label: "label"
};
static events = {
onClick: "click"
};
// Preact component used as a template (hooks could be used here to introduce some logic)
static template = (props) =>
html`<div class="form-check">
<input class="form-check-input" type="checkbox" ...${props} />
<label for=${props.id} class="form-check-label" />
</div>`;
}
);
https://developer.mozilla.org/ru/docs/Web/CSS/:defined
rshb-checkbox {
display: inline;
}
rshb-checkbox:defined {
opacity: 1;
}
rshb-checkbox:not(:defined) {
opacity: 0.5;
}
$ npm run ssr
generates static markup and puts it (asREACT_APP_SSR
environment variable) in.env
file.$ npm start
(as well as$ npm run build
) uses generatedREACT_APP_SSR
environment variable to substitute it into<div id="root">%REACT_APP_SSR%</div>
ofpublic/index.html