Correct patterns

Updated: Sep 24, 2026
Use this checklist before requesting review for a Meta Ray-Ban Display web app interface. It summarizes the safest implementation patterns; the linked guides explain the rationale in detail: Screen patterns, Materials, motion, focus, and portals, Customization and composition, and Accessibility, performance, and validation.

Shell and route structure

  • Render every surface inside one App. It loads the styles and provides the application-level focus, toast, and portal owners.
  • Size html, body, and the mount node to the full viewport, and use var(--uit-color-background-window) for their background.
  • Choose either Page or SubNavigationPager as the route root. A route must not combine both because each owns the route-level structure.
  • Configure the page header through Page’s header* props so Page can coordinate the header and content inset.
  • Give each route one scroll owner per axis: prefer VerticalList for rows and ScrollView for other content. This keeps directional navigation predictable.
  • Pass insetForHeader to the scroll owner when content moves beneath the header.
  • Animate route changes through PageTransition or the React Router integration so focus, page state, and motion remain coordinated.

Content

  • Use ListItem for rows. Let it own showSwitch, showRadioButton, or showSlider through checked / onCheckedChange and sliderValue / onSliderValueChange, keeping each row a single accessible interaction.
  • Dock horizontal actions below the scroller in a ButtonRail or ButtonGroup, with var(--uit-spacing-xsmall) bottom clearance.
  • Place free-floating text on a Panel or StaticContainer to preserve legibility on the additive-light display.
  • Use Modal for structured decision content within a route, and use a dedicated route or separate presenter when that decision must block the application. Use Toast.show(...) for transient outcome feedback.
  • Present a tooltip from its interactable with tooltipText and tooltipMode. Anchor VerticalMenu with getVerticalMenuAnchorProps so the overlay tracks its owner.
  • Provide meaningful alt text for Avatar; an ariaLabel for ScrollView, VerticalList, Pager, and SubNavigationPager; and a localized readMoreLabel for ReadMoreTextView.

Styling and motion

  • Use semantic tokens for color, spacing, corner radius, size, and elevation. Use exported motion constants for durations because durations are not theme tokens.
  • Apply typography through textStyle={TextStyle.*} on TextView or the matching TextAppearanceuit-text-* class on an application element.
  • Define motion with AnimationDurations.*, Interpolators.*, SpringConfigs.*, and createTransition(...) to keep timing consistent.
  • Honor reduced-motion preferences with usePrefersReducedMotion() and reducedMotionDuration(...).
  • Pass icons as an IconSource: inline vector data, a { uri, tinted } object, or a bare URL string. Continue using dedicated URL props such as src, avatarSrc, and bannerSrc for photographic and brand imagery.
  • Let components own smooth-corner geometry, tails, and shape paths.
  • Derive layout from the available viewport so it responds across display sizes.
  • Validate default, focused, pressed, disabled, selected, loading, popup, and scroll states because each can change user-visible rendering or behavior.

Avoid

Structure

  • Avoid building toolkit-looking rows, chips, tags, buttons, or headers from div elements or from a different toolkit component. Use the matching semantic component so its accessibility and interaction behavior are included.
  • Do not render an application-owned ToastContainer; App already presents toasts.
  • Do not duplicate the FocusNavigationProvider or FloatingPortalRootProvider supplied by App. Nest one only when a separate container needs its own focus scope or an embedding host owns the overlay layer.
  • Keep Header under Page ownership. Do not render it independently or next to SubNavigationPager.
  • Avoid placing VerticalList or ListItem inside ScrollView, and avoid a separate list for each section. One scroll owner provides unambiguous focus movement.
  • Keep ordinary ListItem rows free of application-added margins, gaps, dividers, and chevrons that only imply navigation.
  • Use insetForHeader rather than application padding to clear the page header.
  • Use router history and the Back/Escape path instead of adding an in-app back button.

Composition

  • Let Button, Chip, Tag, AppBadge, Header, and ListItem size themselves from content rather than forcing dimensions onto them.
  • Avoid nesting Container, StaticContainer, Surface, Panel, Button, Chip, Tag, or Header inside another member of that set. Each owns a complete surface.
  • A component that is one interaction target must not contain focusable children, and the interface must not show two focused elements at once. These constraints keep focus semantics unambiguous.
  • Treat Switch and RadioButton as presentational. Drive them from ListItem or another interactable that owns activation.
  • Prefer a semantic component over a foundation container. If the toolkit has no matching component, build from the supported foundation APIs rather than imitating one with custom markup.
  • Avoid vertical stacks of primary buttons, non-button children in ButtonRail, and rails used in place of SubNavigationPager.
  • Place a rail or group with its related content actions, not below the header or at the top of a list.

Styling

  • Avoid hardcoded colors, pixel spacing, radii, font sizes, durations, and copied literal fallbacks for tokens. Semantic tokens and motion constants preserve theme consistency.
  • Let the component own smooth-corner paths, tails, and cutouts rather than applying a raw border-radius.
  • Do not override material internals, target generated class names, or select internal nodes from application CSS or DOM queries. Internal structure is not a public API.
  • Keep style focused on layout instead of repainting the toolkit-owned visuals.
  • Preserve avatar badge cutouts rather than imitating them with painted backgrounds.

Behavior

  • Restore the component from its pressed state after activation so its visual state matches the interaction state.
  • Let Header animate icon, avatar, and loading changes; application animation would compete with component-owned transitions.
  • Keep focus stable during loading unless the flow requires a new target.
  • Every focus target must perform a meaningful action. A toast-only action, no-op callback, or placeholder creates an unusable navigation stop.
import { ListItem, Page, VerticalList } from '@wearables-ui-toolkit/mrbd';

function MessageList({ messages }: { messages: Message[] }) {
  return (
    <Page headerText="Messages">
      <VerticalList insetForHeader ariaLabel="Messages">
        {messages.map(message => (
          <ListItem
            key={message.id}
            title={message.senderName}
            subtitle={message.preview}
            avatarSrc={message.avatarUrl}
            avatarAlt={message.senderName}
            timestamp={message.timestamp}
            onClick={() => openThread(message.id)}
          />
        ))}
      </VerticalList>
    </Page>
  );
}
This composition gives each behavior one owner: Page manages the header and system-bar inset, VerticalList manages scrolling, fading edges, the scrollbar, and scroll-to-focused behavior, and ListItem manages row anatomy, material, focus and press state, spacing, and typography.

Avoid this pattern

function BadMessageList({ messages }: { messages: Message[] }) {
  return (
    <div className="custom-page">
      <h1>Messages</h1>
      {messages.map(message => (
        <div
          key={message.id}
          className="custom-row"
          onClick={() => openThread(message.id)}
        >
          {message.senderName}
        </div>
      ))}
    </div>
  );
}
This implementation has several user-visible problems:
  • It bypasses App, Page, VerticalList, and ListItem.
  • It requires custom color, typography, shape, and spacing to imitate an existing component.
  • It provides no focus eligibility, focus material, press state, rubber-band feedback, scroll-to-focused behavior, or accessible row semantics.
  • It cannot restore focus or scroll position after back navigation.