Layout
XML v2 uses Stack, Grid, Card, and FormLayout for composition. The old Columns, Flex, and Hero elements are removed. Tabs and dialogs now use one flat owner component instead of compound trigger, header, and content tags.
Stack
Stack arranges children vertically by default. Set direction="horizontal" for row layout. It replaces Flex as well as simple list-like visual groups.
justify:start,center,end,between,around, orevenly.align:start,center,end, orstretch.gapand padding attributes use the Astryx spacing scale: 0, 0.5, 1, 1.5, 2, 3, 4, 5, 6, 8, or 10.
xml<Stack direction="horizontal" justify="between" align="center" gap="3"><Text i18n="orders.summary" /><Button i18n="orders.open" /></Stack>
Grid
Grid replaces Columns. Use a fixed numeric columns value or create a responsive grid with minColumnWidth, optional maxColumns, and repeat set to fill or fit.
xml<Grid minColumnWidth="280" maxColumns="3" repeat="fit" gap="4"><Card><Text i18n="dashboard.first" /></Card><Card><Text i18n="dashboard.second" /></Card></Grid>
Card
Card groups related content on an Astryx surface. Variants include default, transparent, muted, and named color surfaces. Width and height attributes accept CSS strings or numeric expressions.
xml<Card variant="muted" padding="4" maxWidth="640px"><Stack gap="2"><Heading level="2" i18n="orders.summary" /><Text i18n="orders.description" /></Stack></Card>
FormLayout
FormLayout provides consistent spacing for controls that own their labels and descriptions. Direction can be vertical, horizontal, or horizontal-labels.
xml<FormLayout direction="vertical"><TextInput i18n="customers.fields.name" value="$customer.name" /><TextArea i18n="customers.fields.notes" value="$customer.notes" /></FormLayout>
Page Introductions
Hero and its slot tags are removed. Compose an introduction from Heading, Text, Stack, and optional actions so its semantics stay explicit.
xml<Stack gap="3"><Heading level="1" i18n="orders.title" /><Text as="p" color="secondary" i18n="orders.description" /><Link to="/orders/new" i18n="orders.create" hasUnderline="true" /></Stack>
TabList
TabList replaces Tabs. It requires one or more direct Tab children and an accessible literal label. Each Tab requires a stable value and a label or i18n key. A writable value binding stores the selected tab.
xml<State id="view" value="overview" /><TabList label="Order views" value="$view" hasDivider="true"><Tab value="overview" i18n="orders.tabs.overview"><Text i18n="orders.overview" /></Tab><Tab value="activity" i18n="orders.tabs.activity"><Table data="$events" rowName="event"><TableColumn key="message" field="message" i18n="orders.events.message" /></Table></Tab></TabList>
Dialog
Dialog owns its header, open state, optional trigger, and content. It requires a title or i18n key. Set triggerLabel for an adapter-owned trigger, or bind isOpen to state when another flow controls the dialog.
purpose:required,form, orinfo.variant:standardorfullscreen.triggerVariantandtriggerSize: configure the optional trigger button.
xml<Dialog i18n="orders.create.title" triggerLabel="Create order" purpose="form"><FormLayout><TextInput i18n="orders.fields.name" value="$draft.name" isRequired="true" /></FormLayout><Action action="/api/orders" json="${{ name: draft.name }}"><Button variant="primary" i18n="orders.create.submit" /></Action></Dialog>