# Positioning Utilities for controlling how elements are positioned in the layout using `relative` and `absolute` placement. - [Position Types](#position-types) - [Offset Utilities](#offset-utilities) - [Inset Shortcuts](#inset-shortcuts) - [Negative Offsets](#negative-offsets) - [Arbitrary Values](#arbitrary-values) - [Common Patterns](#common-patterns) - [Combining with Flex](#combining-with-flex) - [Future Work](#future-work) - [Related Documentation](#related-documentation) ```dart // Badge overlay — red dot on an avatar WDiv( className: 'relative', children: [ WDiv(className: 'w-12 h-12 rounded-full bg-gray-300'), WDiv(className: 'absolute top-0 right-0 w-3 h-3 rounded-full bg-red-500'), ], ) ``` ## Position Types Wind maps CSS `position` values to Flutter's `Stack` widget. A `relative` parent establishes a stacking context; `absolute` children are placed inside it using offset utilities. | Wind className | CSS Equivalent | Flutter Widget | |:---------------|:---------------|:---------------| | `relative` | `position: relative` | `Stack` (parent) | | `absolute` | `position: absolute` | `Positioned` (child inside `Stack`) | > [!NOTE] > An `absolute` child must live inside a `relative` parent. Wind will wrap the `relative` container in a `Stack` and each `absolute` child in a `Positioned` widget automatically. ```dart WDiv( className: 'relative w-32 h-32 bg-gray-100', children: [ WDiv(className: 'absolute top-2 left-2 w-8 h-8 bg-blue-500'), ], ) ``` ## Offset Utilities Control the position of `absolute` children using directional offset classes. Values follow the spacing scale (`spacing * n`). | Class | CSS Equivalent | Description | |:------|:---------------|:------------| | `top-{n}` | `top: {n}` | Distance from the top edge | | `right-{n}` | `right: {n}` | Distance from the right edge | | `bottom-{n}` | `bottom: {n}` | Distance from the bottom edge | | `left-{n}` | `left: {n}` | Distance from the left edge | Default spacing scale (base unit = 4px): | Class | Value | |:------|:------| | `top-0` | 0px | | `top-1` | 4px | | `top-2` | 8px | | `top-4` | 16px | | `top-6` | 24px | | `top-8` | 32px | The same scale applies to `right-*`, `bottom-*`, and `left-*`. ```dart WDiv( className: 'relative h-48 bg-white border border-gray-200 rounded-lg', children: [ WDiv( className: 'absolute bottom-4 right-4 px-3 py-2 bg-blue-600 rounded', child: WText('Action', className: 'text-sm text-white'), ), ], ) ``` ## Inset Shortcuts Apply offsets to multiple sides at once with `inset-*` shorthand classes. | Class | Sides Affected | Description | |:------|:---------------|:------------| | `inset-{n}` | top, right, bottom, left | All four sides | | `inset-x-{n}` | left, right | Horizontal sides only | | `inset-y-{n}` | top, bottom | Vertical sides only | | `inset-0` | top, right, bottom, left | Full stretch (fills parent) | ```dart // Full overlay — covers the entire relative parent WDiv( className: 'relative w-full h-48', children: [ WImage(src: 'assets/photo.jpg', className: 'w-full h-full'), // Semi-transparent overlay that fills the image WDiv( className: 'absolute inset-0 bg-black opacity-40', ), WText( 'Caption', className: 'absolute bottom-4 left-4 text-white font-semibold', ), ], ) ``` ```dart // Horizontal inset — leaves top and bottom unconstrained WDiv( className: 'absolute inset-x-4 bottom-4 bg-white rounded p-3', child: WText('Bottom bar'), ) ``` ## Negative Offsets Prefix any offset class with `-` to pull an element outside its parent's boundary. | Class | Value | Description | |:------|:------|:------------| | `-top-{n}` | negative top | Pulls element above the parent | | `-right-{n}` | negative right | Pulls element to the right of the parent | | `-bottom-{n}` | negative bottom | Pulls element below the parent | | `-left-{n}` | negative left | Pulls element to the left of the parent | | `-inset-{n}` | negative all sides | Expands element beyond all four parent edges | ```dart // Notification badge — overlaps the top-right corner of an icon button WDiv( className: 'relative', children: [ WDiv(className: 'w-10 h-10 rounded bg-gray-200 flex items-center justify-center'), WDiv( className: 'absolute -top-1 -right-1 w-4 h-4 rounded-full bg-red-500 flex items-center justify-center', child: WText('3', className: 'text-[10px] text-white font-bold'), ), ], ) ``` ## Arbitrary Values Use bracket notation when you need an exact pixel value not in the theme scale. Only `px` values are supported — percentage (`%`) offsets are not supported because Flutter's `Positioned` widget uses logical pixels, not relative units. ```dart // Exact pixel value WDiv(className: 'absolute top-[24px] left-[12px]') // Mixed — precise multi-side offset WDiv(className: 'absolute top-[12px] right-[8px] bottom-[12px] left-[8px]') ``` ## Common Patterns ### Badge Overlay A notification dot positioned on top of an avatar or icon. ```dart WDiv( className: 'relative w-12 h-12', children: [ WDiv(className: 'w-12 h-12 rounded-full bg-indigo-500'), WDiv( className: 'absolute -top-1 -right-1 w-5 h-5 rounded-full bg-red-500 border-2 border-white flex items-center justify-center', child: WText('2', className: 'text-[9px] text-white font-bold'), ), ], ) ``` ### Floating Action Button (FAB) An action button pinned to the bottom-right corner of a scrollable view. ```dart WDiv( className: 'relative flex-1', children: [ WDiv( className: 'w-full h-full overflow-y-auto p-4', child: WText('Scrollable content...'), ), WDiv( className: 'absolute bottom-6 right-6 w-14 h-14 rounded-full bg-blue-600 flex items-center justify-center shadow-lg', child: WIcon(Icons.add_outlined, className: 'text-white'), ), ], ) ``` ### Full Overlay A semi-transparent scrim that covers an entire card or image. ```dart WDiv( className: 'relative rounded-xl overflow-hidden', children: [ WImage(src: 'assets/hero.jpg', className: 'w-full h-48 object-cover'), WDiv(className: 'absolute inset-0 bg-gradient-to-t from-black/60 to-transparent'), WDiv( className: 'absolute bottom-0 left-0 right-0 p-4', child: WText('Hero Title', className: 'text-white text-lg font-bold'), ), ], ) ``` ## Combining with Flex `relative` and `absolute` compose naturally with flex layouts. The `relative` container itself can be a flex row or column — the `Stack` wraps around the flex widget, and `absolute` children are layered on top. ```dart // Navigation bar with an absolute badge on the icon WDiv( className: 'flex flex-row items-center justify-between px-4 py-3 bg-white border-b border-gray-200', children: [ WText('Inbox', className: 'text-base font-semibold text-gray-900'), WDiv( className: 'relative', children: [ WIcon(Icons.notifications_outlined, className: 'text-gray-700'), WDiv( className: 'absolute -top-1 -right-1 w-4 h-4 rounded-full bg-red-500', ), ], ), ], ) ``` > [!NOTE] > When you add `absolute` children to a flex item, Wind promotes that item to a `Stack`. The flex layout of the parent is preserved. ## Future Work The following position types are tracked but not yet implemented in v1: | Class | Status | |:------|:-------| | `fixed` | Deferred — maps to Flutter's `Overlay`/`Stack` at the root level | | `sticky` | Deferred — requires custom `SliverPersistentHeader` integration | Until these land, use `Overlay` directly or Flutter's `Stack` at the `Scaffold` body level for fixed positioning. ## Related Documentation - [Flexbox & Layout](./flexbox.md) - [Grid Layout](./grid.md) - [Sizing](../sizing/width.md) - [Spacing](../spacing/padding.md)