Flex
This library is a work-in-progress. We are releasing it early to gather feedback, but it is not ready for production.
Flex components provide a powerful and intuitive way to create flexible layouts using CSS Flexbox. They offer a declarative API with dedicated components for common patterns.
Examples
Live Preview
Basic Row Layout
Items arranged horizontally with default flex-start alignment.
Centered Content
Items centered on both axes.
Space Between
Items distributed with space between them.
Space Around
Items with equal space around them.
Space Evenly
Items with equal space between and around them.
Equal Width Children
Using stretch-children to make all items equal width.
Column Layout
Items stacked vertically using FlexCol.
Wrapping Layout
Items wrap to the next line when needed.
Reverse Direction
Reverse the order of items.
Align Items (Cross Axis)
Different vertical alignments for items of varying heights.
align="flex-start"
align="center"
align="flex-end"
Nested Flex Containers
Combine flex containers to create complex layouts.
Stack and Group (Aliases)
Convenient aliases familiar to Mantine and Chakra UI users.
Stack (FlexCol alias)
Group (FlexRow alias)
Inline Flex
Inline flex containers that only take up as much width as needed.
Multiple inline flex containers on the same line:
Responsive Layouts
Example using .responsive-direction CSS class to control --flex-direction via media queries. Resize your browser to see the effect!
Responsive Gap
Example using .responsive-gap CSS class to control --flex-gap at different viewport widths.
Responsive Justify
Example using .responsive-justify CSS class to control --flex-justify via media queries.
Responsive Card Grid
Example using .responsive-cards CSS class to create a responsive card grid with consumer-defined breakpoints.
View Vue Code
<template>
<section>
<!-- Basic Row Layouts -->
<div class="mbe4">
<h2>Basic Row Layout</h2>
<p class="mbs2">Items arranged horizontally with default flex-start alignment.</p>
</div>
<div class="mbe4">
<VueFlexRow gap="1rem">
<div class="demo-box">Item 1</div>
<div class="demo-box">Item 2</div>
<div class="demo-box">Item 3</div>
</VueFlexRow>
</div>
<!-- Centered -->
<div class="mbe4">
<h2>Centered Content</h2>
<p class="mbs2">Items centered on both axes.</p>
</div>
<div class="mbe4">
<VueFlexRow
gap="1rem"
justify="center"
align="center"
style="min-height: 150px; background: var(--ag-background-secondary); border-radius: 3px;"
>
<div class="demo-box">Centered 1</div>
<div class="demo-box">Centered 2</div>
</VueFlexRow>
</div>
<!-- Space Between -->
<div class="mbe4">
<h2>Space Between</h2>
<p class="mbs2">Items distributed with space between them.</p>
</div>
<div class="mbe4">
<VueFlexRow justify="space-between">
<div class="demo-box">Start</div>
<div class="demo-box">Middle</div>
<div class="demo-box">End</div>
</VueFlexRow>
</div>
<!-- Space Around -->
<div class="mbe4">
<h2>Space Around</h2>
<p class="mbs2">Items with equal space around them.</p>
</div>
<div class="mbe4">
<VueFlexRow justify="space-around">
<div class="demo-box">Item 1</div>
<div class="demo-box">Item 2</div>
<div class="demo-box">Item 3</div>
</VueFlexRow>
</div>
<!-- Space Evenly -->
<div class="mbe4">
<h2>Space Evenly</h2>
<p class="mbs2">Items with equal space between and around them.</p>
</div>
<div class="mbe4">
<VueFlexRow justify="space-evenly">
<div class="demo-box">Item 1</div>
<div class="demo-box">Item 2</div>
<div class="demo-box">Item 3</div>
</VueFlexRow>
</div>
<!-- Stretch Children -->
<div class="mbe4">
<h2>Equal Width Children</h2>
<p class="mbs2">Using <code>stretch-children</code> to make all items equal width.</p>
</div>
<div class="mbe4">
<VueFlexRow
gap="1rem"
:stretch-children="true"
>
<div class="demo-box">Short</div>
<div class="demo-box">Medium length</div>
<div class="demo-box">Longer content here</div>
</VueFlexRow>
</div>
<!-- Column Layout -->
<div class="mbe4">
<h2>Column Layout</h2>
<p class="mbs2">Items stacked vertically using FlexCol.</p>
</div>
<div class="mbe4">
<VueFlexCol gap="1rem">
<div class="demo-box">Row 1</div>
<div class="demo-box">Row 2</div>
<div class="demo-box">Row 3</div>
</VueFlexCol>
</div>
<!-- Wrap -->
<div class="mbe4">
<h2>Wrapping Layout</h2>
<p class="mbs2">Items wrap to the next line when needed.</p>
</div>
<div class="mbe4">
<VueFlexRow
gap="1rem"
wrap="wrap"
style="max-width: 600px;"
>
<div
v-for="i in 8"
:key="i"
class="demo-box"
style="min-width: 120px;"
>
Item {{ i }}
</div>
</VueFlexRow>
</div>
<!-- Reverse -->
<div class="mbe4">
<h2>Reverse Direction</h2>
<p class="mbs2">Reverse the order of items.</p>
</div>
<div class="mbe4">
<VueFlexRow
gap="1rem"
:reverse="true"
>
<div class="demo-box">First (1)</div>
<div class="demo-box">Second (2)</div>
<div class="demo-box">Third (3)</div>
</VueFlexRow>
</div>
<!-- Align Items -->
<div class="mbe4">
<h2>Align Items (Cross Axis)</h2>
<p class="mbs2">Different vertical alignments for items of varying heights.</p>
</div>
<div class="mbe4">
<div style="display: flex; flex-direction: column; gap: 1rem;">
<div>
<p class="mbe2"><strong>align="flex-start"</strong></p>
<VueFlexRow
gap="1rem"
align="flex-start"
style="min-height: 120px; background: var(--ag-background-secondary); border-radius: 3px;"
>
<div class="demo-box">Item 1</div>
<div
class="demo-box"
style="padding: 2rem 1rem;"
>
Tall Item 2
</div>
<div class="demo-box">Item 3</div>
</VueFlexRow>
</div>
<div>
<p class="mbe2"><strong>align="center"</strong></p>
<VueFlexRow
gap="1rem"
align="center"
style="min-height: 120px; background: var(--ag-background-secondary); border-radius: 3px;"
>
<div class="demo-box">Item 1</div>
<div
class="demo-box"
style="padding: 2rem 1rem;"
>
Tall Item 2
</div>
<div class="demo-box">Item 3</div>
</VueFlexRow>
</div>
<div>
<p class="mbe2"><strong>align="flex-end"</strong></p>
<VueFlexRow
gap="1rem"
align="flex-end"
style="min-height: 120px; background: var(--ag-background-secondary); border-radius: 3px;"
>
<div class="demo-box">Item 1</div>
<div
class="demo-box"
style="padding: 2rem 1rem;"
>
Tall Item 2
</div>
<div class="demo-box">Item 3</div>
</VueFlexRow>
</div>
</div>
</div>
<!-- Nested Layouts -->
<div class="mbe4">
<h2>Nested Flex Containers</h2>
<p class="mbs2">Combine flex containers to create complex layouts.</p>
</div>
<div class="mbe4">
<VueFlexCol
gap="1rem"
style="padding: 1rem; background: var(--ag-background-secondary); border-radius: 3px;"
>
<VueFlexRow justify="space-between">
<div class="demo-box demo-box-primary">Header Left</div>
<div class="demo-box demo-box-primary">Header Right</div>
</VueFlexRow>
<VueFlexRow gap="1rem">
<VueFlexCol
gap="0.5rem"
style="flex: 1;"
>
<div class="demo-box demo-box-secondary">Sidebar Item 1</div>
<div class="demo-box demo-box-secondary">Sidebar Item 2</div>
<div class="demo-box demo-box-secondary">Sidebar Item 3</div>
</VueFlexCol>
<div
class="demo-box"
style="flex: 2; padding: 2rem;"
>
Main Content Area
</div>
</VueFlexRow>
<VueFlexRow justify="center">
<div class="demo-box demo-box-primary full-width">Footer</div>
</VueFlexRow>
</VueFlexCol>
</div>
<!-- Stack and Group Aliases -->
<div class="mbe4">
<h2>Stack and Group (Aliases)</h2>
<p class="mbs2">Convenient aliases familiar to Mantine and Chakra UI users.</p>
</div>
<div class="mbe4">
<div style="display: flex; gap: 2rem;">
<div style="flex: 1;">
<p class="mbe2"><strong>Stack (FlexCol alias)</strong></p>
<VueStack gap="1rem">
<div class="demo-box">Stacked 1</div>
<div class="demo-box">Stacked 2</div>
<div class="demo-box">Stacked 3</div>
</VueStack>
</div>
<div style="flex: 1;">
<p class="mbe2"><strong>Group (FlexRow alias)</strong></p>
<VueGroup gap="0.5rem">
<button class="demo-button mie1">Action 1</button>
<button class="demo-button mie1">Action 2</button>
<button class="demo-button">Action 3</button>
</VueGroup>
</div>
</div>
</div>
<!-- Inline Flex -->
<div class="mbe4">
<h2>Inline Flex</h2>
<p class="mbs2">Inline flex containers that only take up as much width as needed.</p>
</div>
<div class="mbe4">
<p class="mbe2">Multiple inline flex containers on the same line:</p>
<div style="display: flex; gap: 1rem; flex-wrap: wrap;">
<VueFlexInline
gap="0.5rem"
style="background: var(--ag-background-secondary); padding: 0.5rem; border-radius: 3px;"
>
<span class="demo-tag">Tag 1</span>
<span class="demo-tag">Tag 2</span>
</VueFlexInline>
<VueFlexInline
gap="0.5rem"
style="background: var(--ag-background-secondary); padding: 0.5rem; border-radius: 3px;"
>
<span class="demo-tag">Tag 3</span>
<span class="demo-tag">Tag 4</span>
</VueFlexInline>
<VueFlexInline
gap="0.5rem"
style="background: var(--ag-background-secondary); padding: 0.5rem; border-radius: 3px;"
>
<span class="demo-tag">Tag 5</span>
<span class="demo-tag">Tag 6</span>
</VueFlexInline>
</div>
</div>
<!-- Responsive Layouts -->
<div class="mbe4">
<h2>Responsive Layouts</h2>
<p class="mbs2">Example using <code>.responsive-direction</code> CSS class to control <code>--flex-direction</code> via media queries. <strong>Resize your browser to see the effect!</strong></p>
</div>
<div class="mbe4">
<ag-flex-row class="responsive-direction">
<div class="demo-box">Item 1</div>
<div class="demo-box">Item 2</div>
<div class="demo-box">Item 3</div>
</ag-flex-row>
</div>
<div class="mbe4">
<h2>Responsive Gap</h2>
<p class="mbs2">Example using <code>.responsive-gap</code> CSS class to control <code>--flex-gap</code> at different viewport widths.</p>
</div>
<div class="mbe4">
<ag-flex-row class="responsive-gap">
<div class="demo-box">Item 1</div>
<div class="demo-box">Item 2</div>
<div class="demo-box">Item 3</div>
</ag-flex-row>
</div>
<div class="mbe4">
<h2>Responsive Justify</h2>
<p class="mbs2">Example using <code>.responsive-justify</code> CSS class to control <code>--flex-justify</code> via media queries.</p>
</div>
<div class="mbe4">
<ag-flex-row class="responsive-justify">
<div class="demo-box">Start</div>
<div class="demo-box">Middle</div>
<div class="demo-box">End</div>
</ag-flex-row>
</div>
<div class="mbe4">
<h2>Responsive Card Grid</h2>
<p class="mbs2">Example using <code>.responsive-cards</code> CSS class to create a responsive card grid with consumer-defined breakpoints.</p>
</div>
<div class="mbe4">
<ag-flex-row class="responsive-cards">
<div
v-for="i in 6"
:key="i"
class="demo-box card-item"
>
Card {{ i }}
</div>
</ag-flex-row>
</div>
</section>
</template>
<script setup lang="ts">
import {
VueFlexRow,
VueFlexCol,
VueFlexInline,
VueStack,
VueGroup,
} from "agnosticui-core/flex/vue";
</script>
<style>
/* Clean demo boxes inspired by the flexbox patterns site */
.demo-box {
padding: 1rem;
margin-inline-end: var(--ag-space-2);
margin-block-end: var(--ag-space-2);
background: var(--ag-blue-100);
border: 1px solid var(--ag-blue-300);
border-radius: 3px;
text-align: center;
font-size: 0.875rem;
color: var(--ag-neutral-900);
}
.demo-box-primary {
background: var(--ag-blue-100);
border-color: var(--ag-blue-300);
color: var(--ag-neutral-900);
}
.demo-box-secondary {
background: var(--ag-purple-100);
border-color: var(--ag-purple-300);
color: var(--ag-neutral-900);
}
.demo-tag {
padding: 0.25rem 0.75rem;
background: var(--ag-background-primary);
border: 1px solid var(--ag-border);
border-radius: 3px;
font-size: 0.875rem;
color: var(--ag-text-primary);
}
.demo-button {
padding: 0.5rem 1rem;
background: var(--ag-primary);
color: var(--ag-white);
border: none;
border-radius: 3px;
font-size: 0.875rem;
cursor: pointer;
}
.demo-button:hover {
background: var(--ag-primary-dark);
}
/* Responsive layouts using CSS custom properties - no !important needed! */
.responsive-direction {
--flex-direction: column;
--flex-gap: 1rem;
}
.responsive-direction .demo-box {
margin-block-end: var(--ag-space-2);
}
@media (min-width: 769px) {
.responsive-direction {
--flex-direction: row;
}
.responsive-direction .demo-box {
margin-inline-end: var(--ag-space-3);
padding-inline: var(--ag-space-8);
white-space: nowrap;
}
}
.responsive-gap {
--flex-gap: 0.5rem;
}
@media (min-width: 641px) and (max-width: 768px) {
.responsive-gap {
--flex-gap: 1rem;
}
}
@media (min-width: 769px) {
.responsive-gap {
--flex-gap: 2rem;
}
}
.responsive-justify {
--flex-gap: 1rem;
--flex-justify: center;
}
@media (min-width: 769px) {
.responsive-justify {
--flex-justify: space-between;
}
}
.responsive-cards {
--flex-direction: column;
--flex-gap: 1rem;
}
@media (min-width: 769px) {
.responsive-cards {
--flex-direction: row;
--flex-wrap: wrap;
--flex-gap: 1.5rem;
}
}
.card-item {
flex: 1 1 calc(33.333% - 1rem);
min-width: 200px;
}
</style>
Live Preview
View Lit / Web Component Code
import { LitElement, html } from "lit";
import "agnosticui-core/flex";
export class FlexLitExamples extends LitElement {
// Render in light DOM to access global utility classes
createRenderRoot() {
return this;
}
render() {
return html`
<style>
/* Clean demo boxes inspired by the flexbox patterns site */
.demo-box {
padding: 1rem;
margin-inline-end: var(--ag-space-2);
margin-block-end: var(--ag-space-2);
background: var(--ag-blue-100);
border: 1px solid var(--ag-blue-300);
border-radius: 3px;
text-align: center;
font-size: 0.875rem;
color: var(--ag-neutral-900);
}
.demo-box-primary {
background: var(--ag-blue-100);
border-color: var(--ag-blue-300);
color: var(--ag-neutral-900);
}
.demo-box-secondary {
background: var(--ag-purple-100);
border-color: var(--ag-purple-300);
color: var(--ag-neutral-900);
}
.demo-tag {
padding: 0.25rem 0.75rem;
background: var(--ag-background-primary);
border: 1px solid var(--ag-border);
border-radius: 3px;
font-size: 0.875rem;
color: var(--ag-text-primary);
}
.demo-button {
padding: 0.5rem 1rem;
background: var(--ag-primary);
color: var(--ag-white);
border: none;
border-radius: 3px;
font-size: 0.875rem;
cursor: pointer;
}
.demo-button:hover {
background: var(--ag-primary-dark);
}
.full-width {
width: 100%;
}
/* Responsive layouts using CSS custom properties - no !important needed! */
.responsive-direction {
--flex-direction: column;
--flex-gap: 1rem;
}
.responsive-direction .demo-box {
margin-block-end: var(--ag-space-2);
}
@media (min-width: 769px) {
.responsive-direction {
--flex-direction: row;
}
.responsive-direction .demo-box {
margin-inline-end: var(--ag-space-3);
padding-inline: var(--ag-space-8);
white-space: nowrap;
}
}
.responsive-gap {
--flex-gap: 0.5rem;
}
@media (min-width: 641px) and (max-width: 768px) {
.responsive-gap {
--flex-gap: 1rem;
}
}
@media (min-width: 769px) {
.responsive-gap {
--flex-gap: 2rem;
}
}
.responsive-justify {
--flex-gap: 1rem;
--flex-justify: center;
}
@media (min-width: 769px) {
.responsive-justify {
--flex-justify: space-between;
}
}
.responsive-cards {
--flex-direction: column;
--flex-gap: 1rem;
}
@media (min-width: 769px) {
.responsive-cards {
--flex-direction: row;
--flex-wrap: wrap;
--flex-gap: 1.5rem;
}
}
.card-item {
flex: 1 1 calc(33.333% - 1rem);
min-width: 200px;
}
</style>
<section>
<!-- Basic Row Layouts -->
<div class="mbe4">
<h2>Basic Row Layout</h2>
<p class="mbs2">Items arranged horizontally with default flex-start alignment.</p>
</div>
<div class="mbe4">
<ag-flex-row style="--flex-gap: 1rem">
<div class="demo-box">Item 1</div>
<div class="demo-box">Item 2</div>
<div class="demo-box">Item 3</div>
</ag-flex-row>
</div>
<!-- Centered -->
<div class="mbe4">
<h2>Centered Content</h2>
<p class="mbs2">Items centered on both axes.</p>
</div>
<div class="mbe4">
<ag-flex-row
style="--flex-gap: 1rem; min-height: 150px; background: var(--ag-background-secondary); border-radius: 3px;"
justify="center"
align="center"
>
<div class="demo-box">Centered 1</div>
<div class="demo-box">Centered 2</div>
</ag-flex-row>
</div>
<!-- Space Between -->
<div class="mbe4">
<h2>Space Between</h2>
<p class="mbs2">Items distributed with space between them.</p>
</div>
<div class="mbe4">
<ag-flex-row justify="space-between">
<div class="demo-box">Start</div>
<div class="demo-box">Middle</div>
<div class="demo-box">End</div>
</ag-flex-row>
</div>
<!-- Space Around -->
<div class="mbe4">
<h2>Space Around</h2>
<p class="mbs2">Items with equal space around them.</p>
</div>
<div class="mbe4">
<ag-flex-row justify="space-around">
<div class="demo-box">Item 1</div>
<div class="demo-box">Item 2</div>
<div class="demo-box">Item 3</div>
</ag-flex-row>
</div>
<!-- Space Evenly -->
<div class="mbe4">
<h2>Space Evenly</h2>
<p class="mbs2">Items with equal space between and around them.</p>
</div>
<div class="mbe4">
<ag-flex-row justify="space-evenly">
<div class="demo-box">Item 1</div>
<div class="demo-box">Item 2</div>
<div class="demo-box">Item 3</div>
</ag-flex-row>
</div>
<!-- Stretch Children -->
<div class="mbe4">
<h2>Equal Width Children</h2>
<p class="mbs2">Using <code>stretch-children</code> to make all items equal width.</p>
</div>
<div class="mbe4">
<ag-flex-row style="--flex-gap: 1rem" stretch-children>
<div class="demo-box">Short</div>
<div class="demo-box">Medium length</div>
<div class="demo-box">Longer content here</div>
</ag-flex-row>
</div>
<!-- Column Layout -->
<div class="mbe4">
<h2>Column Layout</h2>
<p class="mbs2">Items stacked vertically using FlexCol.</p>
</div>
<div class="mbe4">
<ag-flex-col style="--flex-gap: 1rem">
<div class="demo-box">Row 1</div>
<div class="demo-box">Row 2</div>
<div class="demo-box">Row 3</div>
</ag-flex-col>
</div>
<!-- Wrap -->
<div class="mbe4">
<h2>Wrapping Layout</h2>
<p class="mbs2">Items wrap to the next line when needed.</p>
</div>
<div class="mbe4">
<ag-flex-row style="--flex-gap: 1rem; max-width: 600px;" wrap="wrap">
${[...Array(8)].map(
(_, i) => html`
<div class="demo-box" style="min-width: 120px;">Item ${i + 1}</div>
`
)}
</ag-flex-row>
</div>
<!-- Reverse -->
<div class="mbe4">
<h2>Reverse Direction</h2>
<p class="mbs2">Reverse the order of items.</p>
</div>
<div class="mbe4">
<ag-flex-row style="--flex-gap: 1rem" reverse>
<div class="demo-box">First (1)</div>
<div class="demo-box">Second (2)</div>
<div class="demo-box">Third (3)</div>
</ag-flex-row>
</div>
<!-- Align Items -->
<div class="mbe4">
<h2>Align Items (Cross Axis)</h2>
<p class="mbs2">Different vertical alignments for items of varying heights.</p>
</div>
<div class="mbe4">
<div style="display: flex; flex-direction: column; gap: 1rem;">
<div>
<p class="mbe2"><strong>align="flex-start"</strong></p>
<ag-flex-row
style="--flex-gap: 1rem; min-height: 120px; background: var(--ag-background-secondary); border-radius: 3px;"
align="flex-start"
>
<div class="demo-box">Item 1</div>
<div class="demo-box" style="padding: 2rem 1rem;">Tall Item 2</div>
<div class="demo-box">Item 3</div>
</ag-flex-row>
</div>
<div>
<p class="mbe2"><strong>align="center"</strong></p>
<ag-flex-row
style="--flex-gap: 1rem; min-height: 120px; background: var(--ag-background-secondary); border-radius: 3px;"
align="center"
>
<div class="demo-box">Item 1</div>
<div class="demo-box" style="padding: 2rem 1rem;">Tall Item 2</div>
<div class="demo-box">Item 3</div>
</ag-flex-row>
</div>
<div>
<p class="mbe2"><strong>align="flex-end"</strong></p>
<ag-flex-row
style="--flex-gap: 1rem; min-height: 120px; background: var(--ag-background-secondary); border-radius: 3px;"
align="flex-end"
>
<div class="demo-box">Item 1</div>
<div class="demo-box" style="padding: 2rem 1rem;">Tall Item 2</div>
<div class="demo-box">Item 3</div>
</ag-flex-row>
</div>
</div>
</div>
<!-- Nested Layouts -->
<div class="mbe4">
<h2>Nested Flex Containers</h2>
<p class="mbs2">Combine flex containers to create complex layouts.</p>
</div>
<div class="mbe4">
<ag-flex-col
style="--flex-gap: 1rem; padding: 1rem; background: var(--ag-background-secondary); border-radius: 3px;"
>
<ag-flex-row justify="space-between">
<div class="demo-box demo-box-primary">Header Left</div>
<div class="demo-box demo-box-primary">Header Right</div>
</ag-flex-row>
<ag-flex-row style="--flex-gap: 1rem">
<ag-flex-col style="--flex-gap: 0.5rem; flex: 1;">
<div class="demo-box demo-box-secondary">Sidebar Item 1</div>
<div class="demo-box demo-box-secondary">Sidebar Item 2</div>
<div class="demo-box demo-box-secondary">Sidebar Item 3</div>
</ag-flex-col>
<div class="demo-box" style="flex: 2; padding: 2rem;">Main Content Area</div>
</ag-flex-row>
<ag-flex-row justify="center">
<div class="demo-box demo-box-primary full-width">Footer</div>
</ag-flex-row>
</ag-flex-col>
</div>
<!-- Stack and Group Aliases -->
<div class="mbe4">
<h2>Stack and Group (Aliases)</h2>
<p class="mbs2">Convenient aliases familiar to Mantine and Chakra UI users.</p>
</div>
<div class="mbe4">
<div style="display: flex; gap: 2rem;">
<div style="flex: 1;">
<p class="mbe2"><strong>Stack (FlexCol alias)</strong></p>
<ag-stack style="--flex-gap: 1rem">
<div class="demo-box">Stacked 1</div>
<div class="demo-box">Stacked 2</div>
<div class="demo-box">Stacked 3</div>
</ag-stack>
</div>
<div style="flex: 1;">
<p class="mbe2"><strong>Group (FlexRow alias)</strong></p>
<ag-group style="--flex-gap: 0.5rem">
<button class="demo-button mie1">Action 1</button>
<button class="demo-button mie1">Action 2</button>
<button class="demo-button">Action 3</button>
</ag-group>
</div>
</div>
</div>
<!-- Inline Flex -->
<div class="mbe4">
<h2>Inline Flex</h2>
<p class="mbs2">Inline flex containers that only take up as much width as needed.</p>
</div>
<div class="mbe4">
<p class="mbe2">Multiple inline flex containers on the same line:</p>
<div style="display: flex; gap: 1rem; flex-wrap: wrap;">
<ag-flex-inline
style="--flex-gap: 0.5rem; background: var(--ag-background-secondary); padding: 0.5rem; border-radius: 3px;"
>
<span class="demo-tag">Tag 1</span>
<span class="demo-tag">Tag 2</span>
</ag-flex-inline>
<ag-flex-inline
style="--flex-gap: 0.5rem; background: var(--ag-background-secondary); padding: 0.5rem; border-radius: 3px;"
>
<span class="demo-tag">Tag 3</span>
<span class="demo-tag">Tag 4</span>
</ag-flex-inline>
<ag-flex-inline
style="--flex-gap: 0.5rem; background: var(--ag-background-secondary); padding: 0.5rem; border-radius: 3px;"
>
<span class="demo-tag">Tag 5</span>
<span class="demo-tag">Tag 6</span>
</ag-flex-inline>
</div>
</div>
<!-- Responsive Layouts -->
<div class="mbe4">
<h2>Responsive Layouts</h2>
<p class="mbs2">
Example using <code>.responsive-direction</code> CSS class to control
<code>--flex-direction</code> via media queries. <strong>Resize your browser to see
the effect!</strong>
</p>
</div>
<div class="mbe4">
<ag-flex-row class="responsive-direction">
<div class="demo-box">Item 1</div>
<div class="demo-box">Item 2</div>
<div class="demo-box">Item 3</div>
</ag-flex-row>
</div>
<div class="mbe4">
<h2>Responsive Gap</h2>
<p class="mbs2">
Example using <code>.responsive-gap</code> CSS class to control
<code>--flex-gap</code> at different viewport widths.
</p>
</div>
<div class="mbe4">
<ag-flex-row class="responsive-gap">
<div class="demo-box">Item 1</div>
<div class="demo-box">Item 2</div>
<div class="demo-box">Item 3</div>
</ag-flex-row>
</div>
<div class="mbe4">
<h2>Responsive Justify</h2>
<p class="mbs2">
Example using <code>.responsive-justify</code> CSS class to control
<code>--flex-justify</code> via media queries.
</p>
</div>
<div class="mbe4">
<ag-flex-row class="responsive-justify">
<div class="demo-box">Start</div>
<div class="demo-box">Middle</div>
<div class="demo-box">End</div>
</ag-flex-row>
</div>
<div class="mbe4">
<h2>Responsive Card Grid</h2>
<p class="mbs2">
Example using <code>.responsive-cards</code> CSS class to create a responsive card grid
with consumer-defined breakpoints.
</p>
</div>
<div class="mbe4">
<ag-flex-row class="responsive-cards">
${[...Array(6)].map(
(_, i) => html` <div class="demo-box card-item">Card ${i + 1}</div> `
)}
</ag-flex-row>
</div>
</section>
`;
}
}
customElements.define("flex-lit-examples", FlexLitExamples);
Interactive Preview: Click the "Open in StackBlitz" button below to see this example running live in an interactive playground.
View React Code
import {
ReactFlexRow,
ReactFlexCol,
ReactFlexInline,
ReactStack,
ReactGroup,
} from "agnosticui-core/flex/react";
const FlexReactExamples = () => {
return (
<section>
{/* Basic Row Layouts */}
<div className="mbe4">
<h2>Basic Row Layout</h2>
<p className="mbs2">Items arranged horizontally with default flex-start alignment.</p>
</div>
<div className="mbe4">
<ReactFlexRow style={{ "--flex-gap": "1rem" }}>
<div className="demo-box">Item 1</div>
<div className="demo-box">Item 2</div>
<div className="demo-box">Item 3</div>
</ReactFlexRow>
</div>
{/* Centered */}
<div className="mbe4">
<h2>Centered Content</h2>
<p className="mbs2">Items centered on both axes.</p>
</div>
<div className="mbe4">
<ReactFlexRow
style={{
"--flex-gap": "1rem",
minHeight: "150px",
background: "var(--ag-background-secondary)",
borderRadius: "3px",
}}
justify="center"
align="center"
>
<div className="demo-box">Centered 1</div>
<div className="demo-box">Centered 2</div>
</ReactFlexRow>
</div>
{/* Space Between */}
<div className="mbe4">
<h2>Space Between</h2>
<p className="mbs2">Items distributed with space between them.</p>
</div>
<div className="mbe4">
<ReactFlexRow justify="space-between">
<div className="demo-box">Start</div>
<div className="demo-box">Middle</div>
<div className="demo-box">End</div>
</ReactFlexRow>
</div>
{/* Space Around */}
<div className="mbe4">
<h2>Space Around</h2>
<p className="mbs2">Items with equal space around them.</p>
</div>
<div className="mbe4">
<ReactFlexRow justify="space-around">
<div className="demo-box">Item 1</div>
<div className="demo-box">Item 2</div>
<div className="demo-box">Item 3</div>
</ReactFlexRow>
</div>
{/* Space Evenly */}
<div className="mbe4">
<h2>Space Evenly</h2>
<p className="mbs2">Items with equal space between and around them.</p>
</div>
<div className="mbe4">
<ReactFlexRow justify="space-evenly">
<div className="demo-box">Item 1</div>
<div className="demo-box">Item 2</div>
<div className="demo-box">Item 3</div>
</ReactFlexRow>
</div>
{/* Stretch Children */}
<div className="mbe4">
<h2>Equal Width Children</h2>
<p className="mbs2">
Using <code>stretch-children</code> to make all items equal width.
</p>
</div>
<div className="mbe4">
<ReactFlexRow style={{ "--flex-gap": "1rem" }} stretchChildren={true}>
<div className="demo-box">Short</div>
<div className="demo-box">Medium length</div>
<div className="demo-box">Longer content here</div>
</ReactFlexRow>
</div>
{/* Column Layout */}
<div className="mbe4">
<h2>Column Layout</h2>
<p className="mbs2">Items stacked vertically using FlexCol.</p>
</div>
<div className="mbe4">
<ReactFlexCol style={{ "--flex-gap": "1rem" }}>
<div className="demo-box">Row 1</div>
<div className="demo-box">Row 2</div>
<div className="demo-box">Row 3</div>
</ReactFlexCol>
</div>
{/* Wrap */}
<div className="mbe4">
<h2>Wrapping Layout</h2>
<p className="mbs2">Items wrap to the next line when needed.</p>
</div>
<div className="mbe4">
<ReactFlexRow style={{ "--flex-gap": "1rem", maxWidth: "600px" }} wrap="wrap">
{[...Array(8)].map((_, i) => (
<div key={i} className="demo-box" style={{ minWidth: "120px" }}>
Item {i + 1}
</div>
))}
</ReactFlexRow>
</div>
{/* Reverse */}
<div className="mbe4">
<h2>Reverse Direction</h2>
<p className="mbs2">Reverse the order of items.</p>
</div>
<div className="mbe4">
<ReactFlexRow style={{ "--flex-gap": "1rem" }} reverse={true}>
<div className="demo-box">First (1)</div>
<div className="demo-box">Second (2)</div>
<div className="demo-box">Third (3)</div>
</ReactFlexRow>
</div>
{/* Align Items */}
<div className="mbe4">
<h2>Align Items (Cross Axis)</h2>
<p className="mbs2">Different vertical alignments for items of varying heights.</p>
</div>
<div className="mbe4">
<div style={{ display: "flex", flexDirection: "column", gap: "1rem" }}>
<div>
<p className="mbe2">
<strong>align="flex-start"</strong>
</p>
<ReactFlexRow
style={{
"--flex-gap": "1rem",
minHeight: "120px",
background: "var(--ag-background-secondary)",
borderRadius: "3px",
}}
align="flex-start"
>
<div className="demo-box">Item 1</div>
<div className="demo-box" style={{ padding: "2rem 1rem" }}>
Tall Item 2
</div>
<div className="demo-box">Item 3</div>
</ReactFlexRow>
</div>
<div>
<p className="mbe2">
<strong>align="center"</strong>
</p>
<ReactFlexRow
style={{
"--flex-gap": "1rem",
minHeight: "120px",
background: "var(--ag-background-secondary)",
borderRadius: "3px",
}}
align="center"
>
<div className="demo-box">Item 1</div>
<div className="demo-box" style={{ padding: "2rem 1rem" }}>
Tall Item 2
</div>
<div className="demo-box">Item 3</div>
</ReactFlexRow>
</div>
<div>
<p className="mbe2">
<strong>align="flex-end"</strong>
</p>
<ReactFlexRow
style={{
"--flex-gap": "1rem",
minHeight: "120px",
background: "var(--ag-background-secondary)",
borderRadius: "3px",
}}
align="flex-end"
>
<div className="demo-box">Item 1</div>
<div className="demo-box" style={{ padding: "2rem 1rem" }}>
Tall Item 2
</div>
<div className="demo-box">Item 3</div>
</ReactFlexRow>
</div>
</div>
</div>
{/* Nested Layouts */}
<div className="mbe4">
<h2>Nested Flex Containers</h2>
<p className="mbs2">Combine flex containers to create complex layouts.</p>
</div>
<div className="mbe4">
<ReactFlexCol
style={{
"--flex-gap": "1rem",
padding: "1rem",
background: "var(--ag-background-secondary)",
borderRadius: "3px",
}}
>
<ReactFlexRow justify="space-between">
<div className="demo-box demo-box-primary">Header Left</div>
<div className="demo-box demo-box-primary">Header Right</div>
</ReactFlexRow>
<ReactFlexRow style={{ "--flex-gap": "1rem" }}>
<ReactFlexCol style={{ "--flex-gap": "0.5rem", flex: "1" }}>
<div className="demo-box demo-box-secondary">Sidebar Item 1</div>
<div className="demo-box demo-box-secondary">Sidebar Item 2</div>
<div className="demo-box demo-box-secondary">Sidebar Item 3</div>
</ReactFlexCol>
<div className="demo-box" style={{ flex: "2", padding: "2rem" }}>
Main Content Area
</div>
</ReactFlexRow>
<ReactFlexRow justify="center">
<div className="demo-box demo-box-primary full-width">Footer</div>
</ReactFlexRow>
</ReactFlexCol>
</div>
{/* Stack and Group Aliases */}
<div className="mbe4">
<h2>Stack and Group (Aliases)</h2>
<p className="mbs2">Convenient aliases familiar to Mantine and Chakra UI users.</p>
</div>
<div className="mbe4">
<div style={{ display: "flex", gap: "2rem" }}>
<div style={{ flex: "1" }}>
<p className="mbe2">
<strong>Stack (FlexCol alias)</strong>
</p>
<ReactStack style={{ "--flex-gap": "1rem" }}>
<div className="demo-box">Stacked 1</div>
<div className="demo-box">Stacked 2</div>
<div className="demo-box">Stacked 3</div>
</ReactStack>
</div>
<div style={{ flex: "1" }}>
<p className="mbe2">
<strong>Group (FlexRow alias)</strong>
</p>
<ReactGroup style={{ "--flex-gap": "0.5rem" }}>
<button className="demo-button mie1">Action 1</button>
<button className="demo-button mie1">Action 2</button>
<button className="demo-button">Action 3</button>
</ReactGroup>
</div>
</div>
</div>
{/* Inline Flex */}
<div className="mbe4">
<h2>Inline Flex</h2>
<p className="mbs2">Inline flex containers that only take up as much width as needed.</p>
</div>
<div className="mbe4">
<p className="mbe2">Multiple inline flex containers on the same line:</p>
<div style={{ display: "flex", gap: "1rem", flexWrap: "wrap" }}>
<ReactFlexInline
style={{
"--flex-gap": "0.5rem",
background: "var(--ag-background-secondary)",
padding: "0.5rem",
borderRadius: "3px",
}}
>
<span className="demo-tag">Tag 1</span>
<span className="demo-tag">Tag 2</span>
</ReactFlexInline>
<ReactFlexInline
style={{
"--flex-gap": "0.5rem",
background: "var(--ag-background-secondary)",
padding: "0.5rem",
borderRadius: "3px",
}}
>
<span className="demo-tag">Tag 3</span>
<span className="demo-tag">Tag 4</span>
</ReactFlexInline>
<ReactFlexInline
style={{
"--flex-gap": "0.5rem",
background: "var(--ag-background-secondary)",
padding: "0.5rem",
borderRadius: "3px",
}}
>
<span className="demo-tag">Tag 5</span>
<span className="demo-tag">Tag 6</span>
</ReactFlexInline>
</div>
</div>
{/* Responsive Layouts */}
<div className="mbe4">
<h2>Responsive Layouts</h2>
<p className="mbs2">
Example using <code>.responsive-direction</code> CSS class to control{" "}
<code>--flex-direction</code> via media queries.{" "}
<strong>Resize your browser to see the effect!</strong>
</p>
</div>
<div className="mbe4">
<ReactFlexRow className="responsive-direction">
<div className="demo-box">Item 1</div>
<div className="demo-box">Item 2</div>
<div className="demo-box">Item 3</div>
</ReactFlexRow>
</div>
<div className="mbe4">
<h2>Responsive Gap</h2>
<p className="mbs2">
Example using <code>.responsive-gap</code> CSS class to control{" "}
<code>--flex-gap</code> at different viewport widths.
</p>
</div>
<div className="mbe4">
<ReactFlexRow className="responsive-gap">
<div className="demo-box">Item 1</div>
<div className="demo-box">Item 2</div>
<div className="demo-box">Item 3</div>
</ReactFlexRow>
</div>
<div className="mbe4">
<h2>Responsive Justify</h2>
<p className="mbs2">
Example using <code>.responsive-justify</code> CSS class to control{" "}
<code>--flex-justify</code> via media queries.
</p>
</div>
<div className="mbe4">
<ReactFlexRow className="responsive-justify">
<div className="demo-box">Start</div>
<div className="demo-box">Middle</div>
<div className="demo-box">End</div>
</ReactFlexRow>
</div>
<div className="mbe4">
<h2>Responsive Card Grid</h2>
<p className="mbs2">
Example using <code>.responsive-cards</code> CSS class to create a responsive card grid
with consumer-defined breakpoints.
</p>
</div>
<div className="mbe4">
<ReactFlexRow className="responsive-cards">
{[...Array(6)].map((_, i) => (
<div key={i} className="demo-box card-item">
Card {i + 1}
</div>
))}
</ReactFlexRow>
</div>
<style>{`
/* Clean demo boxes inspired by the flexbox patterns site */
.demo-box {
padding: 1rem;
margin-inline-end: var(--ag-space-2);
margin-block-end: var(--ag-space-2);
background: var(--ag-blue-100);
border: 1px solid var(--ag-blue-300);
border-radius: 3px;
text-align: center;
font-size: 0.875rem;
color: var(--ag-neutral-900);
}
.demo-box-primary {
background: var(--ag-blue-100);
border-color: var(--ag-blue-300);
color: var(--ag-neutral-900);
}
.demo-box-secondary {
background: var(--ag-purple-100);
border-color: var(--ag-purple-300);
color: var(--ag-neutral-900);
}
.demo-tag {
padding: 0.25rem 0.75rem;
background: var(--ag-background-primary);
border: 1px solid var(--ag-border);
border-radius: 3px;
font-size: 0.875rem;
color: var(--ag-text-primary);
}
.demo-button {
padding: 0.5rem 1rem;
background: var(--ag-primary);
color: var(--ag-white);
border: none;
border-radius: 3px;
font-size: 0.875rem;
cursor: pointer;
}
.demo-button:hover {
background: var(--ag-primary-dark);
}
.full-width {
width: 100%;
}
/* Responsive layouts using CSS custom properties - no !important needed! */
.responsive-direction {
--flex-direction: column;
--flex-gap: 1rem;
}
.responsive-direction .demo-box {
margin-block-end: var(--ag-space-2);
}
@media (min-width: 769px) {
.responsive-direction {
--flex-direction: row;
}
.responsive-direction .demo-box {
margin-inline-end: var(--ag-space-3);
padding-inline: var(--ag-space-8);
white-space: nowrap;
}
}
.responsive-gap {
--flex-gap: 0.5rem;
}
@media (min-width: 641px) and (max-width: 768px) {
.responsive-gap {
--flex-gap: 1rem;
}
}
@media (min-width: 769px) {
.responsive-gap {
--flex-gap: 2rem;
}
}
.responsive-justify {
--flex-gap: 1rem;
--flex-justify: center;
}
@media (min-width: 769px) {
.responsive-justify {
--flex-justify: space-between;
}
}
.responsive-cards {
--flex-direction: column;
--flex-gap: 1rem;
}
@media (min-width: 769px) {
.responsive-cards {
--flex-direction: row;
--flex-wrap: wrap;
--flex-gap: 1.5rem;
}
}
.card-item {
flex: 1 1 calc(33.333% - 1rem);
min-width: 200px;
}
`}</style>
</section>
);
};
export default FlexReactExamples;
Components
AgnosticUI provides four flex components plus two convenient aliases:
- FlexContainer - Base flex container with full control
- FlexRow - Horizontal layout (defaults to
direction: row, but can be overridden) - FlexCol - Vertical layout (defaults to
direction: column, but can be overridden) - FlexInline - Inline flex container
- Stack - Alias for FlexCol (familiar to Mantine/Chakra users)
- Group - Alias for FlexRow (familiar to Mantine users)
Note: FlexRow, FlexCol, Stack, and Group are convenience components that set default directions. You can override any of their properties using CSS custom properties (see Responsive Control).
Responsive Control
Important: Flex components have no built-in breakpoints. All responsive behavior is controlled by you using CSS custom properties and your own media queries.
You control flex behavior at different breakpoints by setting CSS custom properties like --flex-direction, --flex-gap, --flex-justify, etc. in your own CSS with your own media queries:
.my-responsive-layout {
--flex-direction: column;
--flex-gap: 1rem;
}
@media (min-width: 768px) {
.my-responsive-layout {
--flex-direction: row;
--flex-gap: 2rem;
}
}The component simply reads these CSS custom properties - you define when and how they change.
Overriding Convenience Components
FlexRow, FlexCol, Stack, and Group are just convenience wrappers - they set default directions but you can override them completely with CSS custom properties:
Using FlexCol but overriding to row on large screens:
<ag-flex-col class="responsive-column">
<div>Item 1</div>
<div>Item 2</div>
</ag-flex-col>FlexCol defaults to column, but you can override it:
.responsive-column {
--flex-direction: column;
}Override to row on ultra-wide screens:
@media (min-width: 1920px) {
.responsive-column {
--flex-direction: row;
}
}You don't need to use FlexContainer for responsive layouts - any flex component can be controlled with CSS custom properties.
Usage
TIP
The framework examples below import AgnosticUI as an npm package. Alternatively, you can use the CLI for complete control, AI/LLM visibility, and full code ownership:
npx ag init --framework FRAMEWORK # react, vue, lit, svelte, etc.
npx ag add FlexThe CLI copies source code directly into your project, giving you full visibility and control. After running npx ag add, you'll receive exact import instructions.
Vue
<template>
<div>
<VueFlexRow style="--flex-gap: 1rem">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</VueFlexRow>
<VueFlexCol style="--flex-gap: 1rem" justify="center" align="center">
<div>Centered Item 1</div>
<div>Centered Item 2</div>
</VueFlexCol>
<VueFlexRow justify="space-between">
<div>Start</div>
<div>End</div>
</VueFlexRow>
<VueFlexRow style="--flex-gap: 1rem" :stretch-children="true">
<div>Auto width 1</div>
<div>Auto width 2</div>
<div>Auto width 3</div>
</VueFlexRow>
<VueFlexRow style="--flex-gap: 1rem" wrap="wrap">
<div v-for="i in 10" :key="i">Item {{ i }}</div>
</VueFlexRow>
<VueStack style="--flex-gap: 1rem">
<div>Stacked Item 1</div>
<div>Stacked Item 2</div>
</VueStack>
<VueGroup style="--flex-gap: 0.5rem">
<button>Action 1</button>
<button>Action 2</button>
</VueGroup>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import {
VueFlexRow,
VueFlexCol,
VueStack,
VueGroup,
} from "agnosticui-core/flex/vue";
export default defineComponent({
components: {
VueFlexRow,
VueFlexCol,
VueStack,
VueGroup,
},
});
</script>React
import {
ReactFlexRow,
ReactFlexCol,
ReactStack,
ReactGroup,
} from "agnosticui-core/flex/react";
export default function Example() {
return (
<div>
<ReactFlexRow style={{ "--flex-gap": "1rem" } as React.CSSProperties}>
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</ReactFlexRow>
<ReactFlexCol
style={{ "--flex-gap": "1rem" } as React.CSSProperties}
justify="center"
align="center"
>
<div>Centered Item 1</div>
<div>Centered Item 2</div>
</ReactFlexCol>
<ReactFlexRow justify="space-between">
<div>Start</div>
<div>End</div>
</ReactFlexRow>
<ReactFlexRow
style={{ "--flex-gap": "1rem" } as React.CSSProperties}
stretchChildren={true}
>
<div>Auto width 1</div>
<div>Auto width 2</div>
<div>Auto width 3</div>
</ReactFlexRow>
<ReactFlexRow
style={{ "--flex-gap": "1rem" } as React.CSSProperties}
wrap="wrap"
>
{[...Array(10)].map((_, i) => (
<div key={i}>Item {i + 1}</div>
))}
</ReactFlexRow>
<ReactStack style={{ "--flex-gap": "1rem" } as React.CSSProperties}>
<div>Stacked Item 1</div>
<div>Stacked Item 2</div>
</ReactStack>
<ReactGroup style={{ "--flex-gap": "0.5rem" } as React.CSSProperties}>
<button>Action 1</button>
<button>Action 2</button>
</ReactGroup>
</div>
);
}Lit (Web Components)
import { html } from "lit";
import "agnosticui-core/flex";
const template = html`
<ag-flex-row style="--flex-gap: 1rem">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</ag-flex-row>
<ag-flex-col style="--flex-gap: 1rem" justify="center" align="center">
<div>Centered Item 1</div>
<div>Centered Item 2</div>
</ag-flex-col>
<ag-flex-row justify="space-between">
<div>Start</div>
<div>End</div>
</ag-flex-row>
<ag-flex-row style="--flex-gap: 1rem" stretch-children>
<div>Auto width 1</div>
<div>Auto width 2</div>
<div>Auto width 3</div>
</ag-flex-row>
<ag-flex-row style="--flex-gap: 1rem" wrap="wrap">
${[...Array(10)].map((_, i) => html`<div>Item ${i + 1}</div>`)}
</ag-flex-row>
`;Props
All flex components share the same props from FlexContainerProps:
| Prop | Type | Default | Description |
|---|---|---|---|
direction | 'row' | 'row-reverse' | 'column' | 'column-reverse' | 'row' | Flex direction |
wrap | 'nowrap' | 'wrap' | 'wrap-reverse' | 'nowrap' | Whether items wrap |
justify | 'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around' | 'space-evenly' | 'flex-start' | Main axis alignment |
align | 'flex-start' | 'flex-end' | 'center' | 'baseline' | 'stretch' | 'stretch' | Cross axis alignment |
alignContent | 'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around' | 'space-evenly' | 'stretch' | 'stretch' | Multi-line alignment |
inline | boolean | false | Use inline-flex |
reverse | boolean | false | Reverse the direction |
stretchChildren | boolean | false | Apply flex: 1 1 auto to children |
Note: FlexRow defaults direction to 'row', FlexCol defaults to 'column', and FlexInline sets inline to true. These are just defaults - you can override any property using CSS custom properties like --flex-direction, --flex-wrap, --flex-justify, --flex-align, etc. (See Responsive Control).
Gap: There is no gap prop. Control spacing using the --flex-gap CSS custom property (defaults to var(--ag-space-0, 0)). See the Available CSS Custom Properties table below.
CSS Shadow Parts
| Part | Description |
|---|---|
ag-flex-container | The slot wrapper element |
Responsive Design
Flex components provide full responsive control through CSS custom properties combined with your own media queries. Use CSS classes with media queries to define responsive behavior:
Vue
<template>
<VueFlexRow class="responsive-layout">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</VueFlexRow>
</template>
<style scoped>
.responsive-layout {
--flex-direction: column;
--flex-gap: 0.5rem;
}
@media (min-width: 768px) {
.responsive-layout {
--flex-direction: row;
--flex-gap: 1.5rem;
}
}
</style>React
import { ReactFlexRow } from "agnosticui-core/flex/react";
export default function ResponsiveExample() {
return (
<ReactFlexRow className="responsive-layout" gap="1rem">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</ReactFlexRow>
);
}.responsive-layout {
--flex-direction: column;
--flex-gap: 0.5rem;
}
@media (min-width: 768px) {
.responsive-layout {
--flex-direction: row;
--flex-gap: 1.5rem;
}
}Lit (Web Components)
<ag-flex-row class="responsive-layout">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</ag-flex-row>.responsive-layout {
--flex-direction: column;
--flex-gap: 0.5rem;
}
@media (min-width: 768px) {
.responsive-layout {
--flex-direction: row;
--flex-gap: 1.5rem;
}
}Understanding display: contents and its implications
The FlexContainer component (and by extension, FlexRow, FlexCol, Stack, and Group) utilizes display: contents on its host element. This CSS property removes the container from the accessibility tree and the box tree, making its children appear as direct children of its parent.
Benefits (Layout Flexibility):
- Seamless integration with parent layouts: Your flex component can be used directly within any parent CSS Grid or Flexbox layout (e.g.,
display: grid; gap: 2rem;) without creating invalid nesting or extra wrapper divs. The items inside yourFlexContainereffectively become the items of the grid/flex parent. This offers powerful layout flexibility.
Inconveniences (Spacing Limitations):
- Host element spacing: You cannot apply
margin,border,padding, orbackgrounddirectly to theFlexContainerhost element itself to space it from its siblings or define its own visual boundaries. These properties will not have an effect due todisplay: contents. - Workaround for spacing: To add space between a
FlexContainerand its siblings, you must use a parent wrapper with agapproperty or apply margins directly to theFlexContainer's siblings.
Best Practice for Consumers:
Documented behavior: This is an intentional design choice for maximum layout flexibility. Always refer to this documentation for understanding how to style and space
FlexContainercomponents.Wrapping for external spacing: If you need to apply margins, borders, or backgrounds directly to the conceptual "box" of your
FlexContainer, wrap it in adivand apply styles to the wrapper.Overriding
display: contents(Advanced): For advanced use cases where you must have the host element generate its own box (e.g., to apply a background or margin directly), you can override the defaultdisplayproperty using the--host-displayCSS custom property:css/* Allows consumer to change display externally */ ag-flex-container { --host-display: flex; /* Or block, grid, etc. */ }By setting
--host-displaytoflex(orblock,grid, etc.), theFlexContainerwill behave like a regular flex item, and you will be able to apply properties likemargin,border, andbackgrounddirectly to it. Be aware that this will alter its integration with parent grid/flex layouts.
Available CSS Custom Properties
Control flex behavior using these CSS custom properties:
| Property | Custom Property | Values |
|---|---|---|
| Direction | --flex-direction | row, row-reverse, column, column-reverse |
| Wrap | --flex-wrap | nowrap, wrap, wrap-reverse |
| Justify | --flex-justify | flex-start, flex-end, center, space-between, space-around, space-evenly |
| Align | --flex-align | flex-start, flex-end, center, baseline, stretch |
| Gap | --flex-gap | Any valid CSS gap value (e.g., 1rem, 20px, var(--ag-space-4)) |
Responsive Patterns
Use your own media queries to control flex properties at different breakpoints. Here are common patterns (you define your own breakpoints):
Example: Stack on small screens, row on larger screens
.responsive-direction {
--flex-direction: column;
--flex-gap: 1rem;
}
@media (min-width: 769px) {
.responsive-direction {
--flex-direction: row;
}
}Example: Different gap sizes at different viewport widths
.responsive-gap {
--flex-gap: 0.5rem;
}
@media (min-width: 641px) and (max-width: 768px) {
.responsive-gap {
--flex-gap: 1rem;
}
}
@media (min-width: 769px) {
.responsive-gap {
--flex-gap: 2rem;
}
}Example: Center content on small screens, space-between on larger screens
.responsive-justify {
--flex-justify: center;
--flex-gap: 1rem;
}
@media (min-width: 769px) {
.responsive-justify {
--flex-justify: space-between;
}
}Note: The breakpoints shown (641px, 769px, etc.) are just examples. You can use any breakpoints that fit your design.
Design Tokens
Flex components work seamlessly with AgnosticUI design tokens for spacing:
<ag-flex-row gap="var(--ag-space-4)">...</ag-flex-row>
<ag-flex-col gap="var(--ag-space-2)">...</ag-flex-col>
<ag-flex-row gap="1rem">...</ag-flex-row>
<ag-flex-row gap="2rem 1rem">...</ag-flex-row>