@gaia-awesome/components
v0.1.0
Published
Gaia custom web components built with Lit and Web Awesome design tokens.
Readme
Gaia Components
Custom Gaia web components built with Lit and TypeScript, designed to sit beside Web Awesome.
Install
npm install @gaia-awesome/components @gaia-awesome/theme @awesome.me/webawesome@awesome.me/webawesome is a peer dependency. Gaia components are a layer on
top of Web Awesome; they do not replace Web Awesome's loader, CDN, asset, or
base-path setup.
Configure Web Awesome the same way Web Awesome documents it: use its CDN loader,
or import @awesome.me/webawesome/dist/styles/webawesome.css, cherry-pick the
wa-* components your app uses, and call Web Awesome's setBasePath() or use
data-webawesome when self-hosted assets need an explicit base path. Gaia does
not provide a replacement Web Awesome loader or asset setup.
import "@awesome.me/webawesome/dist/styles/webawesome.css";
import "@gaia-awesome/theme/styles/gaia.css";
import "@awesome.me/webawesome/dist/components/button/button.js";
import "@gaia-awesome/components";Apply the Gaia theme classes to the document root when using
@gaia-awesome/theme/styles/gaia.css.
<html class="wa-theme-gaia wa-palette-gaia"></html>Page-shell apps can import the shell kit instead of the whole component package:
import "@awesome.me/webawesome/dist/components/card/card.js";
import "@gaia-awesome/components/page-shell.js";import "@gaia-awesome/components/page.js";Package exports
@gaia-awesome/components: registers and exports the component set.@gaia-awesome/components/page-shell.js: registers the Gaia page-shell kit.@gaia-awesome/components/page.js: registers and exports<gwc-page>.@gaia-awesome/components/custom-elements-jsx.d.ts: JSX types for React 19+ custom elements.@gaia-awesome/components/components/*.js: cherry-pick component entrypoints.@gaia-awesome/components/custom-elements.json: custom element metadata for tooling.
The public component API is generated from source into
API.md, custom-elements.json, and
the JSX types exported by @gaia-awesome/components/custom-elements-jsx.d.ts. Run
vp run @gaia-awesome/components#generate:api after changing component
JSDoc, properties, events, parts, or custom properties.
Page shell components can also be cherry-picked:
import "@gaia-awesome/components/page.js";
import "@gaia-awesome/components/components/page-navigation.js";Build and verify
This package builds with vp pack and package-local tsdown configuration in
vite.config.ts.
vp run @gaia-awesome/components#build
vp test
npm_config_cache=/private/tmp/npm-cache-gaia npm pack --dry-runThe components target Web Awesome >=3.6.0 <4 and Lit >=3 <4, matching Web
Awesome's Lit dependency range. Gaia Design-owned custom elements use the final
gwc- prefix and follow Web Awesome's component naming style. Renaming a
gwc-* element is a breaking change. They do not subclass Web Awesome
internals. They compose with Web Awesome through standard custom elements,
slots, events, and shared design tokens.
Ownership model
wa-*elements and their public APIs belong to Web Awesome.gwc-*custom elements belong to@gaia-awesome/components.- Gaia-owned component-local custom properties use
--gwc-*. - Gaia-owned data attributes use
data-gaia-*. - Gaia-owned custom events use
gwc-*.
Composition patterns
Use shadow DOM for Gaia components by default. GwcElement applies Gaia host
styles and the generated internal Web Awesome shadow theme bridge, so private
nested wa-* elements receive Gaia's theme without becoming public styling
surface. Use light DOM only for concrete Web Awesome interoperability cases that
require real light-DOM children, such as menu items slotted into a Web Awesome
dropdown.
Page Shell Kit
@gaia-awesome/components/page-shell.js is the canonical entrypoint for Gaia
page shells. It registers:
gwc-pagegwc-page-menu-togglegwc-page-aside-togglegwc-page-menu-pingwc-page-navigationgwc-page-nav-itemgwc-page-nav-groupgwc-page-user-card
Use <gwc-page> as the canonical Gaia SaaS shell. It owns the full-height
desktop sidebar, pinned/unpinned behavior, optional aside, mobile drawer state,
outside-click closing, and persisted shell preferences. Apps still import any
Web Awesome primitives they place in their own shell content. This is the reason
to choose it over Web Awesome's generic <wa-page>: Gaia adds product-app shell
state and sidebar behavior, while Web Awesome remains the source for generic
page and layout composition.
Most gwc-page slots are optional. Empty header, main-header,
navigation-header, navigation, navigation-footer, and aside regions are
hidden, so apps opt in only to the sections they actually render.
gwc-page includes a keyboard skip link that targets #main-content. If the
page does not already provide that id, the shell creates a hidden
skip-to-content-target automatically inside the main content area.
The Gaia theme page-shell partial owns the responsive utility classes used
inside page content: .wa-mobile-only is hidden for desktop gwc-page views,
and .wa-desktop-only is hidden for mobile views. Import
@gaia-awesome/theme/styles/gaia.css when using those utilities.
<gwc-page
mobile-breakpoint="920"
storage-scope="approval"
default-sidebar-open
default-sidebar-pinned
persist-sidebar
>
<header slot="header">
<gwc-page-menu-toggle controls="app-navigation"></gwc-page-menu-toggle>
<div data-gaia-page-region="actions"></div>
</header>
<gwc-page-navigation id="app-navigation" slot="navigation">
<gwc-page-nav-item item-id="tasks" href="/tasks" current>My tasks</gwc-page-nav-item>
<gwc-page-nav-item item-id="history" href="/history">My history</gwc-page-nav-item>
</gwc-page-navigation>
<main
id="main-content"
class="wa-grid wa-gap-m"
style="--min-column-size: var(--gaia-page-card-min-width, 24rem)"
>
<wa-card></wa-card>
</main>
</gwc-page>Main content layout is explicit. Use Web Awesome layout utilities such as
wa-grid, wa-stack, wa-cluster, wa-split, wa-flank, wa-frame, gap
classes, and wa-span-grid instead of adding Gaia-specific grid wrappers.
React
React 19+ supports custom elements natively. Use Gaia components directly as
gwc-* elements, just like Web Awesome's wa-* elements.
import "@awesome.me/webawesome/dist/components/card/card.js";
import "@gaia-awesome/components/page-shell.js";
export function Shell() {
return (
<gwc-page mobile-breakpoint="920" default-sidebar-open>
<gwc-page-navigation
slot="navigation"
ongwc-nav-activate={(event) => {
event.preventDefault();
navigate(event.detail.item.href);
}}
>
<gwc-page-nav-item item-id="tasks" href="/tasks" current>
My tasks
</gwc-page-nav-item>
</gwc-page-navigation>
<wa-card></wa-card>
</gwc-page>
);
}For TypeScript, add Web Awesome's JSX types and Gaia's JSX types to your React declaration file.
import type {
CustomCssProperties as WebAwesomeCustomCssProperties,
CustomElements as WebAwesomeCustomElements,
} from "@awesome.me/webawesome/dist/custom-elements-jsx.d.ts";
import type {
CustomCssProperties as GaiaCustomCssProperties,
CustomElements as GaiaCustomElements,
} from "@gaia-awesome/components/custom-elements-jsx.d.ts";
declare module "react" {
namespace JSX {
interface IntrinsicElements extends WebAwesomeCustomElements, GaiaCustomElements {}
}
interface CSSProperties extends WebAwesomeCustomCssProperties, GaiaCustomCssProperties {}
}Custom event props use React 19's native custom-element event syntax: prefix the
actual event name with on, preserve dashes, and keep the name lowercase, for
example ongwc-nav-activate and ongwc-page-sidebar-change.
Angular
Angular apps should keep CUSTOM_ELEMENTS_SCHEMA for Web Awesome and Gaia custom
elements, import the Gaia component entrypoints during bootstrap, and bind Gaia
events in templates:
<gwc-page-navigation
aria-label="Angular demo pages"
(gwc-nav-activate)="handleNavigation($event)"
></gwc-page-navigation><gwc-page-menu-toggle>
Hamburger toggle for the closest enclosing Gaia page shell. With <gwc-page>,
desktop clicks toggle sidebar-open and mobile clicks toggle the internal
navigation drawer. Render this in the page header.
Attributes
| Attribute | Type | Default | Description |
| ----------------- | -------- | ----------------------- | -------------------------------------------------------------- |
| controls | string | "" | Optional ID of the navigation region controlled by the button. |
| button-label | string | "Toggle navigation" | ARIA label on the underlying button. |
| expanded-label | string | "Collapse navigation" | ARIA label when the sidebar or drawer is open. |
| collapsed-label | string | "Expand navigation" | ARIA label when the sidebar or drawer is closed. |
Styling model
This component renders its composed <wa-button> inside its shadow root. It
does not expose ::part() styling API; prefer attributes and properties over
styling internals.
<gwc-page-aside-toggle>
Icon button for toggling a Gaia page shell aside region. Place it in the page
header or actions area and point controls at the aside element ID. It flips
aside-open on the nearest <gwc-page>.
<gwc-page-aside-toggle
controls="page-ai-aside"
expanded-label="Hide AI chat"
collapsed-label="Show AI chat"
icon-name="wand-magic-sparkles"
></gwc-page-aside-toggle>Attributes
| Attribute | Type | Default | Description |
| ----------------- | -------- | ---------------- | ------------------------------------------------- |
| controls | string | "" | ID of the aside element controlled by the toggle. |
| button-label | string | "Toggle aside" | Fixed ARIA label on the underlying button. |
| expanded-label | string | "Hide aside" | ARIA label when the aside is open. |
| collapsed-label | string | "Show aside" | ARIA label when the aside is closed. |
| icon-name | string | "sidebar-flip" | Web Awesome icon name rendered inside the button. |
Styling model
This component renders its composed <wa-button> inside its shadow root. It
does not expose ::part() styling API; prefer attributes and properties over
styling internals.
<gwc-page-user-card>
Dropdown trigger identity row designed for sidebar footers. Renders an avatar +
name compactly by default; when used as the trigger of a <wa-dropdown>, the
dropdown sets aria-expanded="true" on the host and the card expands (shows the
details slot, swaps the chevron, applies the active fill). Consumers can also
set expanded directly when controlling the trigger state without a dropdown.
The host is keyboard activatable with Enter and Space when used as a custom
dropdown trigger; it is not intended as a general profile card.
Attributes
| Attribute | Type | Default | Description |
| ---------- | --------- | ------- | ----------------------------------------------------------------------------------- |
| expanded | boolean | false | Applies the expanded trigger presentation outside dropdown-managed aria-expanded. |
Slots
| Slot | Description |
| --------- | ------------------------------------------------------------- |
| avatar | The avatar element (typically <wa-avatar>). |
| name | Primary identity text. |
| details | Secondary text (email, role, …). Hidden in the compact state. |
CSS parts
| Part | Description |
| --------- | ---------------------------------------------- |
| base | The identity container (name + details stack). |
| name | The primary text wrapper. |
| details | The secondary text wrapper. |
| chevron | The chevron icon wrapper. |
CSS custom properties
| Property | Description |
| ------------------------------ | ----------------------------------------------- |
| --gwc-page-user-card-padding | Sets the host padding. |
| --gwc-page-user-card-gap | Sets the gap between avatar, text, and chevron. |
<gwc-page-menu-pin>
Pin/unpin menu item for the closest enclosing <gwc-page>. Place inside a
<wa-dropdown> (typically anchored to the navigation-footer). When clicked,
flips sidebar-pinned. It renders a normal icon dropdown item, and the label
flips between pin-label and unpin-label to match current state.
Attributes
| Attribute | Type | Default | Description |
| ------------- | -------- | -------------- | --------------------------------------------------- |
| pin-label | string | "Pin menu" | Label shown when the sidebar is currently unpinned. |
| unpin-label | string | "Unpin menu" | Label shown when the sidebar is currently pinned. |
Styling model
This component renders its composed <wa-dropdown-item> in light DOM because
<wa-dropdown> expects real menu items in its light-DOM menu content. It does
not expose ::part() styling API; prefer attributes and properties over styling
internals.
<gwc-page-navigation>
Standard page-shell navigation landmark. Product apps provide declarative
<gwc-page-nav-item> and <gwc-page-nav-group> children. Framework apps should
map their own route data to those elements rather than assigning object-model
input to the component.
<gwc-page-navigation slot="navigation" aria-label="Approval navigation">
<gwc-page-nav-item item-id="tasks" href="/tasks" current> My tasks </gwc-page-nav-item>
<gwc-page-nav-group label="Configuration" default-expanded>
<gwc-page-nav-item item-id="roles" href="/configuration/roles"> Roles </gwc-page-nav-item>
</gwc-page-nav-group>
</gwc-page-navigation>Apps should filter unauthorized routes before rendering navigation elements. The navigation component is not an authorization or routing engine.
GaiaPageNavItem
export type GaiaPageNavItem = {
id: string;
label: string;
href?: string;
icon?: string;
current?: boolean;
disabled?: boolean;
badge?: string | number;
};For navigation groups, expanded is controlled by the app.
defaultExpanded sets the initial uncontrolled state and then lets user
interaction keep the group open or closed inside the component.
Events
gwc-nav-activate is cancelable. Prevent it to stop the original link click.
type GaiaPageNavActivateDetail = {
item: GaiaPageNavItem;
originalEvent: Event;
};gwc-expanded-change is emitted when a navigation group is opened or closed by
the user. In controlled mode, update expanded from this event.
type GaiaPageNavExpandedChangeDetail = {
expanded: boolean;
originalEvent: Event;
};CSS parts
| Part | Description |
| ------ | -------------------------------- |
| base | The internal navigation element. |
Main Content Cards
Use Web Awesome's <wa-card> as the reusable white content surface inside the
Gaia page shell. Place one or more cards inside the page's default slot. For
multi-card layouts, use Web Awesome layout utilities on the parent.
<main
id="main-content"
class="wa-grid wa-gap-m"
style="--min-column-size: var(--gaia-page-card-min-width, 24rem)"
>
<wa-card role="region" aria-labelledby="tasks-title">
<h2>Pending approvals</h2>
...
</wa-card>
</main><wa-card> does not own grid placement. Keep row and column decisions in the
parent layout with Web Awesome utilities or app CSS. Use card header,
footer, and action slots when a page panel needs structured sections.
<gwc-page-nav-item> and <gwc-page-nav-group>
Declarative navigation elements for static HTML, server-rendered apps, and framework-generated navigation lists.
<gwc-page-navigation slot="navigation" aria-label="Approval navigation">
<gwc-page-nav-item item-id="tasks" href="/tasks" icon="inbox" current>
My tasks
</gwc-page-nav-item>
<gwc-page-nav-group label="Configuration" icon="gear" default-expanded>
<gwc-page-nav-item item-id="roles" href="/configuration/roles"> Roles </gwc-page-nav-item>
</gwc-page-nav-group>
</gwc-page-navigation>Use expanded for controlled groups and listen for gwc-expanded-change to
mirror user toggles back into app state. Use default-expanded for an
uncontrolled group that should start open. Uncontrolled groups also start open
when a descendant <gwc-page-nav-item current> is present.
There is no @gaia-awesome/components/styles/gaia.css export yet. Keep base
styles inside components until a real light-DOM composition component needs a
global stylesheet.
