@zerops/web-components
v0.4.0
Published
Zerops UI as framework-agnostic web components — drop a <script>, get live, deployable recipe cards on any page.
Readme
@zerops/web-components
Zerops UI as framework-agnostic web components. Each element is a self-registering ES module entry — import it for its side effect and use the tag anywhere: plain HTML, React, Vue, Svelte, anything that renders DOM.
Angular is fully bundled inside (zoneless, shared across all elements on the page); the package has no peer dependencies.
Setup
Every page using the components needs the stylesheet and the fonts once:
<link href="https://fonts.googleapis.com/css2?family=Geologica:[email protected]&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons+Outlined" rel="stylesheet">import '@zerops/web-components/style.css';<zerops-recipe-card>
import '@zerops/web-components/recipe-card';Self-fetching mode
The element fetches the recipe from the public Zerops API (CORS-open) at load:
<zerops-recipe-card slug="nestjs-minimal"></zerops-recipe-card>Captured-data mode — no API call
Ship the recipe snapshot with your page and the card renders instantly:
import showcase from '@zerops/web-components/recipes/zerops-showcase.json';
const card = document.querySelector('zerops-recipe-card');
await customElements.whenDefined('zerops-recipe-card');
card.recipeData = showcase;React
import { useEffect, useRef } from 'react';
import '@zerops/web-components/recipe-card';
import '@zerops/web-components/style.css';
import type { ZeropsRecipeCardElement } from '@zerops/web-components/recipe-card';
export function ZeropsRecipeCard({ slug, recipeData, onDeployed }: {
slug?: string;
recipeData?: object;
onDeployed?: (appUrl: string) => void;
}) {
const ref = useRef<ZeropsRecipeCardElement>(null);
useEffect(() => {
const el = ref.current;
if (!el) return;
const handler = (e: CustomEvent<string>) => onDeployed?.(e.detail);
el.addEventListener('deployed', handler);
return () => el.removeEventListener('deployed', handler);
}, [onDeployed]);
useEffect(() => {
if (!recipeData) return;
customElements.whenDefined('zerops-recipe-card').then(() => {
if (ref.current) ref.current.recipeData = recipeData;
});
}, [recipeData]);
return <zerops-recipe-card ref={ref} slug={slug} />;
}With React 19 you can also set recipeData directly as a JSX prop (React assigns it as a DOM property); the wrapper above works on 18 and 19.
For TypeScript JSX, augment the intrinsic elements once:
declare module 'react' {
namespace JSX {
interface IntrinsicElements {
'zerops-recipe-card': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & {
slug?: string;
'api-base'?: string;
'app-url'?: string;
};
}
}
}Attributes / properties
| Name | Attribute | Default | |
|------|-----------|---------|-|
| slug | slug | — | Catalog slug to self-fetch |
| recipeData | recipe-data (JSON string) | — | Captured recipe; wins over slug |
| apiBase | api-base | https://api.zerops.io | Public API origin |
| appUrl | app-url | https://app.zerops.io | Detail/deploy link origin |
Events (CustomEvents on the element)
| Event | detail | |
|-------|----------|-|
| deployed | string | Deploy clicked; the app URL that was opened |
| detailOpened | — | A detail/title link was clicked |
<zerops-network-diagram>
The homepage's animated network diagram (project shell, infra core, L7 routing, live request traces) for any recipe environment:
import '@zerops/web-components/network-diagram';<!-- self-fetching -->
<zerops-network-diagram slug="zerops-showcase" environment="highly-available-production"></zerops-network-diagram>// captured-data mode — same snapshot the recipe card uses
import showcase from '@zerops/web-components/recipes/zerops-showcase.json';
const el = document.querySelector('zerops-network-diagram');
await customElements.whenDefined('zerops-network-diagram');
el.recipeData = showcase;| Property | Attribute | Default | Purpose |
|---|---|---|---|
| slug | slug | — | Catalog slug to self-fetch |
| recipeData | recipe-data (JSON string) | — | Captured recipe; wins over slug |
| environment | environment | highly-available-production | Environment to draw (falls back to the recipe default) |
| mode | mode | auto | Project core: auto derives serious/lightweight from the environment's core service; lightweight/serious force it |
| apiBase | api-base | https://api.zerops.io | Public API origin |
The trace animation pauses off-viewport and respects prefers-reduced-motion.
<zerops-managed-service-diagram>
The homepage's animated managed-services showcase — health checks, automatic failover, backups, and scaling panels. Fully static, no attributes:
import '@zerops/web-components/managed-service-diagram';<zerops-managed-service-diagram></zerops-managed-service-diagram>Animations start when the element scrolls into view.
<zerops-containers-cards>
The System Containers comparison — App Containers / System Containers / Full VMs cards with the zerops.yaml terminal. Fully static, no attributes:
import '@zerops/web-components/containers-cards';<zerops-containers-cards></zerops-containers-cards>Known caveats
- The stylesheet includes a CSS-layered normalize that can nudge host-page base styles.
- Recipe snapshots under
recipes/are frozen at package publish time; useslugmode for always-current data.
