Askr
UI & Components

Structures

Use structures with the current published Askr packages.

  • @askrjs/ui0.0.13
  • @askrjs/themes0.0.13

How to use structures

Structures should use the standard themed surface unless the application is deliberately implementing its own design system on top of @askrjs/ui.

  1. Import the themed component from @askrjs/themes/components; use @askrjs/ui directly only when building a custom visual system.
  2. Keep structures labels, state, and application actions visible at the call site instead of styling internal DOM nodes.
  3. Verify keyboard behavior, focus movement or return, disabled state, and both standard themes.
import { Button, Dialog, DialogContent, DialogTitle, DialogTrigger } from '@askrjs/themes/components';

<Dialog>
  <DialogTrigger asChild><Button>Open settings</Button></DialogTrigger>
  <DialogContent>
    <DialogTitle>Project settings</DialogTitle>
    <ProjectSettings />
  </DialogContent>
</Dialog>

Purpose

`Block` is described in the theme's own docs as "the only layout engine" — the single primitive responsible for spacing, sizing, alignment, and responsive flex direction across the whole component catalog. Higher-level structural pieces like `Container`, `Section`, `Stack`, `Inline`, and `Grid` are built as presets on top of it rather than separate systems, which keeps layout behavior consistent everywhere it's used.

Install and import

Import structural components from the themes catalog: `import { Block, Container, Stack, Section, Grid } from '@askrjs/themes/components'`. Broader layout slots — `Main`, `Sidebar`, `Header`, `Footer`, `Shell` — are exported the same way and are, per the package's own docs, "semantic Block presets, not independent layout engines."

Live examples

Implement live examples at the structures boundary: make inputs visible at the call site, keep cleanup with the work that created it, and render the success, unavailable, and failure states where a user can act on them.

Anatomy

Block's layout props are genuinely extensive: `padding`, `paddingX`, `paddingY`, `margin`, `width`, `height`, `direction`, `align`, `justify`, `gap`, `grow`, `shrink`, `background`, `radius`, `shadow`, `sticky`, `top`, and `zIndex`, among others. Every one of these accepts a `ResponsiveValue<T>` — either a bare value or a `Partial<Record<'base' | 'sm' | 'md' | 'lg' | 'xl', T>>` — so a single prop can carry a full mobile-first breakpoint schedule.

State model

Structural components are stateless by design — they're pure layout, driven entirely by the props you pass in on each render, not by internal open/closed or selected flags the way interactive components are. `direction`, for instance, is just one of Block's `ResponsiveValue` props, resolving to `"row" | "column" | "row-reverse" | "column-reverse"` at whichever breakpoint applies.

Keyboard and accessibility

Because Block and its presets render plain structural elements rather than interactive controls, there's no dedicated keyboard contract to document here — accessibility for structural components mostly comes down to choosing sensible native elements and letting content inside them (buttons, links, form controls) carry their own accessible behavior. `Main`, `Header`, and similar presets do map to meaningful landmark elements, which is worth preserving when you customize them.

Styling and tokens

Block-owned layout variables are explicitly called out as part of the public theme contract, meaning they resolve through theme tokens rather than hard-coded pixel values, so retheming spacing or breakpoints doesn't require touching component code. Responsive behavior is additive and mobile-first: base styles apply everywhere, and `sm`, `md`, `lg`, `xl` values layer on top via `min-width` media queries, never the other way around.

API

The real Block prop types are worth knowing by name: `BlockSpace` for padding/gap/margin scale (`"0" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "page"`), `BlockSize` for width/height (`"auto" | "full" | "screen" | "content" | "sidebar" | "page" | "sm" | "md" | "lg" | "xl"`), `BlockAlign`, `BlockJustify`, `BlockBackground`, `BlockRadius`, `BlockShadow`, and `BlockZIndex` (`"header" | "sticky" | "fixed" | "dropdown" | "modal" | "popover" | "toast" | "tooltip"`). Field and InputGroup, by contrast, are pure visual composition wrappers with no comparable layout prop surface — they exist to arrange form controls, not to lay out arbitrary content.

Edge cases

Because Block is the only layout engine, resist the temptation to reach for raw flexbox or grid CSS around it for one-off adjustments — inconsistent layout approaches are exactly what the single-engine design is meant to prevent. Also remember that broad slots like `main`, `sidebar`, and `navbar` are semantic presets over Block, not independent components with their own prop vocabulary, so their responsive behavior follows the same breakpoint rules as everything else.

See Portals and Layers for how overlay content escapes normal document flow rather than being laid out by Block, and Customization for how Block's own CSS variables participate in the token override system.