Skip to content

Flex

Experimental Alpha

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

Vue
Lit
React
Live Preview

Basic Row Layout

Items arranged horizontally with default flex-start alignment.

Item 1
Item 2
Item 3

Centered Content

Items centered on both axes.

Centered 1
Centered 2

Space Between

Items distributed with space between them.

Start
Middle
End

Space Around

Items with equal space around them.

Item 1
Item 2
Item 3

Space Evenly

Items with equal space between and around them.

Item 1
Item 2
Item 3

Equal Width Children

Using stretch-children to make all items equal width.

Short
Medium length
Longer content here

Column Layout

Items stacked vertically using FlexCol.

Row 1
Row 2
Row 3

Wrapping Layout

Items wrap to the next line when needed.

Item 1
Item 2
Item 3
Item 4
Item 5
Item 6
Item 7
Item 8

Reverse Direction

Reverse the order of items.

First (1)
Second (2)
Third (3)

Align Items (Cross Axis)

Different vertical alignments for items of varying heights.

align="flex-start"

Item 1
Tall Item 2
Item 3

align="center"

Item 1
Tall Item 2
Item 3

align="flex-end"

Item 1
Tall Item 2
Item 3

Nested Flex Containers

Combine flex containers to create complex layouts.

Header Left
Header Right
Sidebar Item 1
Sidebar Item 2
Sidebar Item 3
Main Content Area
Footer

Stack and Group (Aliases)

Convenient aliases familiar to Mantine and Chakra UI users.

Stack (FlexCol alias)

Stacked 1
Stacked 2
Stacked 3

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:

Tag 1Tag 2Tag 3Tag 4Tag 5Tag 6

Responsive Layouts

Example using .responsive-direction CSS class to control --flex-direction via media queries. Resize your browser to see the effect!

Item 1
Item 2
Item 3

Responsive Gap

Example using .responsive-gap CSS class to control --flex-gap at different viewport widths.

Item 1
Item 2
Item 3

Responsive Justify

Example using .responsive-justify CSS class to control --flex-justify via media queries.

Start
Middle
End

Responsive Card Grid

Example using .responsive-cards CSS class to create a responsive card grid with consumer-defined breakpoints.

Card 1
Card 2
Card 3
Card 4
Card 5
Card 6
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;
Open in StackBlitz

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:

css
.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:

html
<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:

css
.responsive-column {
  --flex-direction: column;
}

Override to row on ultra-wide screens:

css
@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:

bash
npx ag init --framework FRAMEWORK # react, vue, lit, svelte, etc.
npx ag add Flex

The 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
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
tsx
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)
typescript
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:

PropTypeDefaultDescription
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
inlinebooleanfalseUse inline-flex
reversebooleanfalseReverse the direction
stretchChildrenbooleanfalseApply 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

PartDescription
ag-flex-containerThe 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
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
tsx
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>
  );
}
css
.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)
html
<ag-flex-row class="responsive-layout">
  <div>Item 1</div>
  <div>Item 2</div>
  <div>Item 3</div>
</ag-flex-row>
css
.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 your FlexContainer effectively 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, or background directly to the FlexContainer host element itself to space it from its siblings or define its own visual boundaries. These properties will not have an effect due to display: contents.
  • Workaround for spacing: To add space between a FlexContainer and its siblings, you must use a parent wrapper with a gap property or apply margins directly to the FlexContainer'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 FlexContainer components.

  • Wrapping for external spacing: If you need to apply margins, borders, or backgrounds directly to the conceptual "box" of your FlexContainer, wrap it in a div and 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 default display property using the --host-display CSS custom property:

    css
    /* Allows consumer to change display externally */
    ag-flex-container {
      --host-display: flex; /* Or block, grid, etc. */
    }

    By setting --host-display to flex (or block, grid, etc.), the FlexContainer will behave like a regular flex item, and you will be able to apply properties like margin, border, and background directly 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:

PropertyCustom PropertyValues
Direction--flex-directionrow, row-reverse, column, column-reverse
Wrap--flex-wrapnowrap, wrap, wrap-reverse
Justify--flex-justifyflex-start, flex-end, center, space-between, space-around, space-evenly
Align--flex-alignflex-start, flex-end, center, baseline, stretch
Gap--flex-gapAny 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

css
.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

css
.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

css
.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:

html
<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>