Components, icons and config
Your own React components under components/ (any React works; defineComponent adds typed, defaulted props and a catalog entry), icons from any Iconify set or your icons/*.svg, and the app's public config values.
On this page
Pages render on the server and hydrate in the browser, so a render must give the same output in both: take now from useClock, format dates with an explicit time zone, and render browser-only libraries with client: true or lazyComponent.
Components
defineComponentfunction
A component with typed, defaulted props and an entry in the console's component catalog. client: true renders skeleton on the server and in the first paint, then the component: use it for browser-only libraries (maps, canvases, editors). A plain React component works too.
defineComponent<S extends Record<string, AnyProp>>(def: { name: string; props?: S; client?: boolean; skeleton?: ReactNode; render: (props: { [K in keyof S]: Val<S[K]> }) => ReactNode; }): ComponentType<Props<S>> & { info: ComponentInfo }Parameters
| Name | Type | Description |
|---|---|---|
defrequired | { name: string; props?: S; client?: boolean; skeleton?: ReactNode; render: (props: { [K in keyof S]: Val<S[K]> }) => ReactNode; } | name, props (built with p), client, skeleton and render(props). |
- Returns
- The component, with
info(name, props, client). - Errors
- Does not throw.
- Permissions
- None.
import { defineComponent, p } from "@appbricx/ui";
export const StatCard = defineComponent({
name: "StatCard",
props: { label: p.string(), value: p.number(), cols: p.number().default(3) },
render: ({ label, value }) => (
<div className="rounded-lg border p-4"><p>{label}</p><p className="text-2xl">{value}</p></div>
),
});Source: internal/kernel/appsdk/ui/component.tsx:66
lazyComponentfunction
A component whose code is its own chunk, loaded after the first paint, with skeleton until then. Use it for a library that touches window as soon as it is imported, or to keep a heavy chart out of the route's budget (100 KB gzip per route).
lazyComponent<P extends object>(load: () => Promise<{ default: ComponentType<P> }>, opts: { skeleton?: ReactNode } = {}): ComponentType<P>Parameters
| Name | Type | Description |
|---|---|---|
loadrequired | () => Promise<{ default: ComponentType<P> }> | |
optsoptional | { skeleton?: ReactNode } |
- Returns
ComponentType<P>- Errors
- Does not throw.
- Permissions
- None.
import { lazyComponent } from "@appbricx/ui";
const BookingsChart = lazyComponent(() => import("../components/BookingsChart"), {
skeleton: <div className="h-64 animate-pulse rounded bg-stone-100" />,
});Source: internal/kernel/appsdk/ui/component.tsx:94
p.stringfunction
A text prop. .default(v) makes it optional with a value; .optional() makes it optional.
p.string(): Prop<string, false>- Returns
Prop<string, false>- Errors
- Does not throw.
- Permissions
- None.
props: { title: p.string(), subtitle: p.string().optional() }Source: internal/kernel/appsdk/ui/component.tsx:34
p.uuidfunction
An id prop (a row's id).
p.uuid(): Prop<string, false>- Returns
Prop<string, false>- Errors
- Does not throw.
- Permissions
- None.
props: { booking: p.uuid() }Source: internal/kernel/appsdk/ui/component.tsx:35
p.numberfunction
A number prop.
p.number(): Prop<number, false>- Returns
Prop<number, false>- Errors
- Does not throw.
- Permissions
- None.
props: { cols: p.number().default(3) }Source: internal/kernel/appsdk/ui/component.tsx:36
p.boolfunction
A true/false prop.
p.bool(): Prop<boolean, false>- Returns
Prop<boolean, false>- Errors
- Does not throw.
- Permissions
- None.
props: { compact: p.bool().default(false) }Source: internal/kernel/appsdk/ui/component.tsx:37
p.jsonfunction
Any JSON value, typed by you.
p.json<T>(): Prop<T, false>- Returns
Prop<T, false>- Errors
- Does not throw.
- Permissions
- None.
props: { series: p.json<Array<{ day: string; n: number }>>() }Source: internal/kernel/appsdk/ui/component.tsx:38
Icons
<Icon>component
An icon from any Iconify set (lucide:calendar-check, ph:confetti-duotone) or your own icons/<name>.svg (app:<name>). Names must be literals: the build collects them into one SVG sprite, so there is no JavaScript per icon and currentColor themes it. size (default 1em) and title (an icon that means something on its own).
Icon<N extends string>({ name, size = "1em", title, className, ...rest }: IconProps<N>): ElementParameters
| Name | Type | Description |
|---|---|---|
{ name, size = "1em", title, className, ...rest }required | IconProps<N> |
- Returns
Element- Errors
- An
app:name that isn't in icons/ is a type error; an unknown Iconify name fails the build.
- An
- Permissions
- None.
import { Icon } from "@appbricx/ui";
<Icon name="lucide:calendar-check" />
<Icon name="app:mark" size={24} title="Teamday" />Source: internal/kernel/appsdk/ui/icon.tsx:27
Config and clock
useConfigfunction
The app's public config values: the config entries app.config.ts marks public: true, set per environment and the same in the server render. Typed from app.config.ts.
useConfig(): PublicConfig- Returns
PublicConfig- Errors
- Does not throw.
- Permissions
- Only public values reach the browser.
const { SUPPORT_PHONE } = useConfig();
{SUPPORT_PHONE ? <footer>Help: {SUPPORT_PHONE}</footer> : null}Source: internal/kernel/appsdk/ui/app.tsx:474
useClockfunction
The app's time zone and locale, as the server render used them, so dates format the same on the server and in the browser (a mismatch is a hydration error and a verify failure).
useClock(): Clock- Returns
Clock- Errors
- Does not throw.
- Permissions
- None.
const { tz, locale } = useClock();
const when = new Intl.DateTimeFormat(locale ?? "en-GB", { timeZone: tz ?? "UTC", dateStyle: "medium" }).format(new Date(row.starts_at));Source: internal/kernel/appsdk/ui/app.tsx:469
Types
interface IconProps<N extends string = string> extends Omit<React.SVGProps<SVGSVGElement>, "name"> {
name: N & IconName<N>;
/** Width and height (default 1em: the text's size). */
size?: number | string;
/** A label for an icon that means something on its own (else it is decorative). */
title?: string;
}Source: internal/kernel/appsdk/ui/icon.tsx:19
interface Clock {
tz?: string;
locale?: string;
}Source: internal/kernel/appsdk/ui/app.tsx:88