Skip to main content
Wildo.ai Coming soon

Components and theming

Let containers explain how their content should behave

Share container behavior for layout, focus and content instead of leaving each child to guess.

One dialog owns the keyboard-focus cycle within its controls.

Let containers explain how their content should behave

A dialog, a card and the application shell have different responsibilities. A surface policy describes those responsibilities—such as focus handling, scrolling or content presentation—in a form participating children can observe.

Keep visual choices in the theme and shared behavior in the policy. A local exception can then change the behavior without making nearby components infer it from CSS.

Example — A dialog with one focus owner

A dialog keeps keyboard interaction inside its active content while it is open. When the host dialog already manages focus, the inner surface leaves that job to the host instead of installing a second trap.

For engineers

Wonder Todos assigns the main landmark to its canonical shell in design-system.config.ts:

  surfacePolicies: {
    [SurfaceVariant.SHELL]: {
      a11y: {
        landmarkRole: 'main',
      },
    },
  },

This is a selected configuration block. The shell default does not claim main, allowing an application to choose its owner. A nested shell used only as layout context must avoid claiming a second main region.

Surface merges framework defaults, theme policy, application policy and its call-site policyOverride, in that order. The result is available through useSurfacePolicy; supported values are also emitted as CSS variables and attributes. Current Surface is exported from @wildo-ai/saas-frontend-lib.

Make inheritance an explicit choice

This illustrative composition gives the parent a single-line text policy and lets its child opt into that policy. useSurfacePolicy exposes the resolved value to participating child components; merely nesting arbitrary HTML does not apply truncation to it.

import { Surface } from '@wildo-ai/saas-frontend-lib';
import { SurfaceVariant } from '@wildo-ai/presets-components-models';

<Surface variant={SurfaceVariant.BASE}
  policyOverride={{ content: { textTruncation: 'ellipsis-line' } }}>
  <Surface variant={SurfaceVariant.BASE}
    policyOverride={{ content: { textTruncation: 'inherit' } }}>
    {content}
  </Surface>
</Surface>

content represents application content using the framework’s policy-aware text primitives. With inherit, the child resolves the parent’s value. With reset, it resolves the framework default for that slot instead. Omitting a slot uses the normal variant/theme/application policy chain; nesting alone is not an instruction to copy every parent value.

Give a dialog one behavior owner

When adapting a dialog primitive that already owns focus trapping and scroll lock, use Surface on its content root with asChild and a11yManagedByHost. The existing host must supply a labelled dialog and keyboard/focus behavior; the flag delegates those responsibilities, it does not implement them.

<Surface variant={SurfaceVariant.BASE} asChild a11yManagedByHost
  policyOverride={{ a11y: { landmarkRole: 'none' } }}>
  <DialogContent aria-labelledby={titleId}>
    <DialogTitle id={titleId}>{dialogTitle}</DialogTitle>
    {content}
  </DialogContent>
</Surface>

This is an adapter fragment inside an already configured dialog root. DialogContent and DialogTitle denote that host’s primitives; titleId, the localized title and content belong to the application. Use the host’s public API rather than duplicating its focus handlers. The framework’s standard dialog already composes its own Surface, so do not add a second wrapper around it merely to repeat this pattern.

Connect policy to the CSS consumers

The runtime’s stylesheet contract requires:

@import "tailwindcss";
@import "tw-animate-css";
@plugin "@wildo-ai/saas-frontend-lib/tailwind";

The plugin translates policy variables into layout and presentation rules. Animation utilities supply overlay transitions; duration tokens alone do not create their keyframes.

Policy concernWhere the effect is applied
Focus and scroll containmentSurface’s shared handlers, unless a11yManagedByHost delegates them to the host
Landmark and accessible nameThe container that owns the region, with header or explicit labelling
Content and automatic field presentationParticipating text, table and generated-field components
Portal target and mobile shapeOverlay hosts and portal adapters

A policy is not global CSS that transforms arbitrary children. Use the framework’s participating primitives, and adapt third-party containers deliberately. For a local visual tweak use classes; for a change children must understand use policyOverride, without setting the same property through both paths.

Building a B2B product or an internal tool?

Wildo is not self-service yet. Tell us what you have in mind and we will say plainly whether it fits, and what happens next.