react-extensible-engine
v1.0.1
Published
React Extensible Engine (REE) - a lightweight, extensible React + TypeScript component library template.
Maintainers
Readme
React Extensible Engine (REE)
A lightweight, extensible component library template for building websites with React + TypeScript + TSX. REE ships ten reusable, accessible components plus a small engine layer that lets you register your own components and render them from plain data.
- All React components are
.tsx, all utilities/helpers are.ts - Typed props,
classNamesupport, and basic accessibility on every component - Normal React architecture (no custom DOM engine)
Installation
npm install react-extensible-engine
# peer dependencies
npm install react react-domQuick start
import { Engine, Button, Card } from "react-extensible-engine";
export default function App() {
return (
<Engine theme="default">
<Card title="Welcome" subtitle="React Extensible Engine">
<p>Build UIs from reusable, typed components.</p>
<Button variant="primary" onClick={() => alert("Hi!")}>
Get started
</Button>
</Card>
</Engine>
);
}Components
| Component | Key props |
| --- | --- |
| Button | variant, size, loading, fullWidth, leftIcon, rightIcon |
| Card | title, subtitle, media, footer, onSelect |
| Navbar | brand, links, actions, sticky |
| Sidebar | open, onClose, side, items, header, footer |
| HamburgerMenu | open / defaultOpen, onOpenChange, label |
| Modal | open, onClose, title, footer, closeOnBackdrop |
| Dropdown | items, value, onSelect, open, onOpenChange |
| Tabs | items, value / defaultValue, onChange |
| Toast | open, message, variant, duration, onClose |
| ChatBox | messages, onSend, typing, placeholder |
Every component accepts className so you can style it with any CSS solution.
Class names are prefixed with ree- (e.g. ree-button ree-button--primary).
Engine layer
Engine (alias of EngineProvider) holds a component registry and an event bus.
Renderer turns a declarative node tree into React elements using that registry.
import { Engine, Renderer, Button, Card } from "react-extensible-engine";
const nodes = [
{
type: "Card",
props: { title: "From data" },
children: [{ type: "Button", props: { variant: "secondary" }, children: "Click" }],
},
];
export function Page() {
return (
<Engine components={{ Card, Button }}>
<Renderer nodes={nodes} />
</Engine>
);
}Simple example
import { useState } from "react";
import { Engine, Navbar, HamburgerMenu, Modal, Toast, Tabs, Button } from "react-extensible-engine";
export function Demo() {
const [open, setOpen] = useState(false);
const [toast, setToast] = useState(false);
return (
<Engine>
<Navbar
brand="REE"
links={[{ label: "Home", href: "/", active: true }]}
actions={<HamburgerMenu>Menu content</HamburgerMenu>}
sticky
/>
<Tabs
items={[
{ id: "one", label: "One", content: <Button onClick={() => setOpen(true)}>Open modal</Button> },
{ id: "two", label: "Two", content: <Button onClick={() => setToast(true)}>Show toast</Button> },
]}
/>
<Modal open={open} onClose={() => setOpen(false)} title="Hello">
Modal body content.
</Modal>
<Toast open={toast} message="Saved successfully" variant="success" onClose={() => setToast(false)} />
</Engine>
);
}Utilities and helpers
utils/dom.ts—isBrowser,lockBodyScroll,focusFirst,scrollToBottomutils/events.ts—useEscapeKey,useClickOutside,EventBusutils/styles.ts—cx,scoped,mergeStyleshelpers/createElement.tsx—createElement,withDefaultshelpers/mergeProps.ts—mergePropshelpers/componentUtils.ts—useComponentId,useControllableState,useToggle,useMounted,useLatest
License
MIT
