Skip to content

@vibe-labs/design-components-responsive

Framework-agnostic responsive layout components for the Vibe Design System. Provides container, grid, and stack components with container-query-based responsive behaviour via data attributes.

Installation

css
@import "@vibe-labs/design-components-responsive";
ts
import type { ResponsiveGridStyleProps } from "@vibe-labs/design-components-responsive/types";

Contents

Tokens (responsive.css)

Component-specific tokens in @layer vibe.tokens:

TokenDefaultPurpose
--responsive-grid-gapvar(--space-4)Grid default gap
--responsive-stack-gapvar(--space-4)Stack default gap

Generated Styles (responsive.g.css)

All styles in @layer vibe.components.

Responsive Container

Establishes a container query context. Defaults to inline-size (the common case).

Base class: .responsive-container

AttributeValuesDefault
data-typeinline · size · normalinline
data-namemain · sidebar · card · panel

Responsive Grid

A 12-column grid with container-query-driven column counts. Set the default with data-cols, then override per breakpoint with data-cols-{bp}.

Base class: .responsive-grid

AttributeValuesPurpose
data-cols1–12Default column count
data-cols-xs1–12Columns at xs (480px)
data-cols-sm1–12Columns at sm (640px)
data-cols-md1–12Columns at md (768px)
data-cols-lg1–12Columns at lg (1024px)
data-cols-xl1–12Columns at xl (1280px)
data-cols-2xl1–12Columns at 2xl (1536px)

Gap defaults to var(--responsive-grid-gap). Override with spacing utilities (.gap-2, .gap-8, etc.) or inline style.

Responsive Stack

Flex column by default, switches to row at the specified breakpoint. Container-query-based.

Base class: .responsive-stack

AttributeValuesPurpose
data-breakpointxs · sm · md · lg · xl · 2xlBreakpoint to switch to row

Gap defaults to var(--responsive-stack-gap). Override with spacing utilities or inline style.

TypeScript Types

ts
// Breakpoints
export const Breakpoints: readonly ["xs", "sm", "md", "lg", "xl", "2xl"];
export type Breakpoint = "xs" | "sm" | "md" | "lg" | "xl" | "2xl";

// Container
export const ContainerTypes: readonly ["inline", "size", "normal"];
export type ContainerType = "inline" | "size" | "normal";
export const ContainerNames: readonly ["main", "sidebar", "card", "panel"];
export type ContainerName = "main" | "sidebar" | "card" | "panel";
export interface ResponsiveContainerStyleProps { ... }

// Grid
export const GridColumns: readonly [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
export type GridColumn = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
export interface ResponsiveGridStyleProps { ... }

// Stack
export interface ResponsiveStackStyleProps { ... }

Dist Structure

FileDescription
index.cssBarrel — imports both CSS files
responsive.cssComponent token definitions
responsive.g.cssGenerated component CSS
index.jsTypeScript runtime exports
index.d.tsTypeScript type declarations

Dependencies

Runtime (CSS custom properties, not npm):

  • @vibe-labs/design-spacing--space-4 used as default gap
  • @vibe-labs/design-responsive — breakpoint tokens (for documentation; values are duplicated in the generate script)

Build-time:

  • .build/selectors.ts — shared base(), variant(), flag() selector helpers

Build

bash
npm run build

Usage Guide

Import

css
@import "@vibe-labs/design-components-responsive";
ts
import type { ResponsiveGridStyleProps, ResponsiveStackStyleProps } from "@vibe-labs/design-components-responsive/types";

Variants

Container

AttributeValuesDefaultNotes
data-typeinline size normalinlineContainer query axis
data-namemain sidebar card panelNamed container for nested queries

Grid

AttributeValuesNotes
data-cols1–12Default column count
data-cols-xs1–12Override at 480px container width
data-cols-sm1–12Override at 640px container width
data-cols-md1–12Override at 768px container width
data-cols-lg1–12Override at 1024px container width
data-cols-xl1–12Override at 1280px container width
data-cols-2xl1–12Override at 1536px container width

Stack

AttributeValuesNotes
data-breakpointxs sm md lg xl 2xlSwitches from column to row here

Examples

Responsive card grid

html
<div class="responsive-container">
  <div class="responsive-grid" data-cols="1" data-cols-sm="2" data-cols-lg="3" data-cols-xl="4">
    <div class="card">Card 1</div>
    <div class="card">Card 2</div>
    <div class="card">Card 3</div>
    <div class="card">Card 4</div>
  </div>
</div>
html
<div class="responsive-container">
  <div class="responsive-stack" data-breakpoint="md">
    <aside style="width: 240px;">Sidebar</aside>
    <main style="flex: 1;">Main content</main>
  </div>
</div>

Named container (card)

html
<div class="responsive-container" data-name="card">
  <div class="responsive-grid" data-cols="1" data-cols-sm="2">
    <div>Item A</div>
    <div>Item B</div>
  </div>
</div>

Size container (both axes)

html
<div class="responsive-container" data-type="size">
  <div class="responsive-grid" data-cols="2" data-cols-lg="4">
    <div>Cell</div>
    <div>Cell</div>
  </div>
</div>

Full 12-column example

html
<div class="responsive-container">
  <div class="responsive-grid"
    data-cols="1"
    data-cols-xs="2"
    data-cols-md="3"
    data-cols-lg="4"
    data-cols-xl="6"
    data-cols-2xl="12"
  >
    <div>Item</div>
    <div>Item</div>
    <div>Item</div>
  </div>
</div>

With Vue

vue
<template>
  <div class="responsive-container">
    <div
      class="responsive-grid"
      :data-cols="cols"
      :data-cols-sm="colsSm"
      :data-cols-lg="colsLg"
    >
      <slot />
    </div>
  </div>
</template>

<script setup lang="ts">
import type { GridColumn } from "@vibe-labs/design-components-responsive/types";
defineProps<{ cols: GridColumn; colsSm?: GridColumn; colsLg?: GridColumn }>();
</script>

Vibe