Askr documentation
UI & Components

Layout Primitives

Start here for layout: use Block as the general-purpose primitive, then compose Container and Text with exact published prop values.

Example

import { Block, Container, Text } from '@askrjs/themes/components';

<Container paddingY="lg">
  <Block direction="column" gap="md">
    <Text as="strong" size="lg">Projects</Text>
    <Text tone="muted">Active work in this workspace.</Text>
    <ProjectList />
  </Block>
</Container>

Published props

Generated from the TypeScript declarations shipped by the installed package. Named types in the Type column define the accepted values.

BlockOwnProps

Import from @askrjs/themes/components.

PropTypeDefaultDescription
alignalign?: ResponsiveValue<BlockAlign> | undefined;——
asas?: BlockElement | undefined;——
backgroundbackground?: ResponsiveValue<BlockBackground> | undefined;——
borderborder?: ResponsiveValue<boolean> | undefined;——
borderBottomborderBottom?: ResponsiveValue<boolean> | undefined;——
borderRightborderRight?: ResponsiveValue<boolean> | undefined;——
borderTopborderTop?: ResponsiveValue<boolean> | undefined;——
centercenter?: ResponsiveValue<boolean> | undefined;——
childrenchildren?: unknown;——
classNameclassName?: string | undefined;——
directiondirection?: ResponsiveValue<BlockDirection> | undefined;——
gapgap?: ResponsiveValue<BlockSpace> | undefined;——
growgrow?: ResponsiveValue<number | boolean> | undefined;——
heightheight?: ResponsiveValue<BlockSize> | undefined;——
hidehide?: ResponsiveValue<boolean> | undefined;——
justifyjustify?: ResponsiveValue<BlockJustify> | undefined;——
marginmargin?: ResponsiveValue<BlockMargin> | undefined;——
marginXmarginX?: ResponsiveValue<BlockMargin> | undefined;——
marginYmarginY?: ResponsiveValue<BlockMargin> | undefined;——
maxHeightmaxHeight?: ResponsiveValue<BlockSize> | undefined;——
maxWidthmaxWidth?: ResponsiveValue<BlockSize> | undefined;——
minHeightminHeight?: ResponsiveValue<BlockSize> | undefined;——
minWidthminWidth?: ResponsiveValue<BlockSize> | undefined;——
paddingpadding?: ResponsiveValue<BlockSpace> | undefined;——
paddingXpaddingX?: ResponsiveValue<BlockSpace> | undefined;——
paddingYpaddingY?: ResponsiveValue<BlockSpace> | undefined;——
radiusradius?: ResponsiveValue<BlockRadius> | undefined;——
rowFromrowFrom?: BlockRowFrom | undefined;——
shadowshadow?: ResponsiveValue<BlockShadow> | undefined;——
shrinkshrink?: ResponsiveValue<number | boolean> | undefined;——
stickysticky?: boolean | undefined;——
toptop?: ResponsiveValue<BlockSpace> | undefined;——
widthwidth?: ResponsiveValue<BlockSize> | undefined;——
wrapwrap?: ResponsiveValue<boolean> | undefined;——
zIndexzIndex?: ResponsiveValue<BlockZIndex> | undefined;——

ContainerProps

Import from @askrjs/themes/components.

PropTypeDefaultDescription
alignalign?: ResponsiveValue<BlockAlign> | undefined;——
asas?: "div" | undefined;——
backgroundbackground?: ResponsiveValue<BlockBackground> | undefined;——
borderborder?: ResponsiveValue<boolean> | undefined;——
borderBottomborderBottom?: ResponsiveValue<boolean> | undefined;——
borderRightborderRight?: ResponsiveValue<boolean> | undefined;——
borderTopborderTop?: ResponsiveValue<boolean> | undefined;——
centercenter?: ResponsiveValue<boolean> | undefined;——
childrenchildren?: unknown;——
classNameclassName?: string | undefined;——
directiondirection?: ResponsiveValue<BlockDirection> | undefined;——
gapgap?: ResponsiveValue<BlockSpace> | undefined;——
growgrow?: ResponsiveValue<number | boolean> | undefined;——
heightheight?: ResponsiveValue<BlockSize> | undefined;——
hidehide?: ResponsiveValue<boolean> | undefined;——
justifyjustify?: ResponsiveValue<BlockJustify> | undefined;——
marginmargin?: ResponsiveValue<BlockMargin> | undefined;——
marginXmarginX?: ResponsiveValue<BlockMargin> | undefined;——
marginYmarginY?: ResponsiveValue<BlockMargin> | undefined;——
maxHeightmaxHeight?: ResponsiveValue<BlockSize> | undefined;——
minHeightminHeight?: ResponsiveValue<BlockSize> | undefined;——
minWidthminWidth?: ResponsiveValue<BlockSize> | undefined;——
paddingpadding?: ResponsiveValue<BlockSpace> | undefined;——
paddingXpaddingX?: ResponsiveValue<BlockSpace> | undefined;——
paddingYpaddingY?: ResponsiveValue<BlockSpace> | undefined;——
radiusradius?: ResponsiveValue<BlockRadius> | undefined;——
rowFromrowFrom?: BlockRowFrom | undefined;——
shadowshadow?: ResponsiveValue<BlockShadow> | undefined;——
shrinkshrink?: ResponsiveValue<number | boolean> | undefined;——
sizesize?: BlockSize | undefined;——
stickysticky?: boolean | undefined;——
toptop?: ResponsiveValue<BlockSpace> | undefined;——
widthwidth?: ResponsiveValue<BlockSize> | undefined;——
wrapwrap?: ResponsiveValue<boolean> | undefined;——
zIndexzIndex?: ResponsiveValue<BlockZIndex> | undefined;——

TextProps

Import from @askrjs/themes/components.

PropTypeDefaultDescription
asas?: TextElement | undefined;——
childrenchildren?: unknown;——
fontfont?: TextFont | undefined;——
numericnumeric?: TextNumeric | undefined;——
refref?: Ref<HTMLElement>;——
sizesize?: TextSize | undefined;——
tonetone?: TextTone | undefined;——
truncatetruncate?: boolean | undefined;——
weightweight?: TextWeight | undefined;——
wrapwrap?: TextWrap | undefined;——

Purpose

There's no single ApplicationLayout component in Askr — this page is guidance on composing the layout primitives @askrjs/themes does ship (Block, Container, Header, Main, Grid, Shell, ShellNav, ShellMain) into the shell most apps need: a header, a main content area, and consistent page-level spacing. Treat it as a pattern to follow, not an API to import wholesale.

Install and import

Pull the pieces you need from the @askrjs/themes/components barrel (there is no separate @askrjs/themes/core subpath — that name isn't a real entrypoint in the package): Block for general-purpose flex layout, Container for width-constrained content, Header and Main for semantic page regions, and Shell/ShellNav/ShellMain when you want a pre-composed app frame instead of assembling Blocks by hand.

Live examples

A common shell is a Shell containing a ShellNav for top-level navigation and a ShellMain for routed content, each internally built from Block with direction and gap props rather than custom flexbox CSS. For simpler pages, Header plus Main plus a Container wrapping the main content to cap line length is often enough without reaching for Shell at all.

Anatomy

Block is the layout engine underneath nearly everything here — it takes direction, align, justify, gap, padding, and sizing props and renders as whatever native element you specify via as. Header and Main are semantic presets built on top of Block for their respective page landmarks; Shell composes ShellNav and ShellMain into the standard nav-plus-content frame.

State model

Nothing at this level tracks an open/closed or collapsed/expanded flag — these components exist to arrange, not to remember. What looks like state is really configuration: responsiveness flows through Block's ResponsiveValue<T> props, which take either a single value or a per-breakpoint object keyed by base, sm, md, lg, and xl, rather than anything you'd track at runtime.

Keyboard and accessibility

Because Header and Main map to real landmark elements, screen reader users get correct page-region navigation for free as long as you don't override as to something non-semantic. Skip-link patterns and focus order are your responsibility to wire up at the app level — the layout primitives don't provide a built-in skip-to-content mechanism.

Styling and tokens

Every spacing, sizing, and breakpoint prop on Block resolves through the shared token system rather than raw pixel values, so a layout built from Block props stays consistent with the rest of the theme automatically. Follow the mobile-first responsive convention documented in the theme's contract: base styles target narrow screens, and sm/md/lg/xl values layer on as min-width overrides.

API

Block accepts padding, paddingX, paddingY, margin, width, height, direction, align, justify, gap, grow, shrink, sticky, background, border, radius, and shadow, most typed as ResponsiveValue<T> so they can vary per breakpoint. rowFrom (typed BlockRowFrom, one of sm | md | lg | xl) is specifically for switching a stacked mobile layout into a row at a given breakpoint — the standard tool for "stack on mobile, row on desktop" layouts.

Edge cases

Nesting many Blocks with conflicting width/height values can produce layouts that don't collapse the way you expect on narrow screens — test at the documented widths (320, 390, 768, 1024, and desktop) rather than assuming a layout that looks right at one size holds at another. sticky combined with zIndex needs a value from the fixed BlockZIndex set (header, sticky, fixed, dropdown, modal, popover, toast, tooltip) rather than an arbitrary number, so pick the token that matches what the element actually is.

Advanced Layout goes further into sidebar-driven and multi-region shells. Sidebar covers the specific collapsible side-navigation pattern that often pairs with this page's header-plus-main structure. Container and Grid are worth a look for content-width and multi-column needs that a single Block doesn't cover cleanly.