v2.0.0

Core Principles

Five rules that govern all layout in DryUI.

  1. Grid only

    Every layout uses display: grid. Never use display: flex or DryUI layout components like Grid, Stack, or Flex.

  2. Container queries

    Use container-type: inline-size with @container for responsive behavior. Never use @media for sizing breakpoints.

  3. Spacing tokens

    Always use --dry-space-* tokens for gap and padding. Never hardcode pixel values for spacing.

  4. CSS custom properties

    Expose layout configuration as --var custom properties so consumers can override values without touching your CSS.

  5. Scoped styles only

    All layout CSS goes in scoped <style> blocks. No inline styles, no style: directives, no :global(), no !important.

@media is for preferences only

The only valid use of @media queries is for user preference detection — never for sizing.

css
/* ✅ Correct — user preferences */
@media (prefers-reduced-motion: reduce) {
  .animated { animation: none; }
}

@media (prefers-color-scheme: dark) {
  /* theme adjustments */
}

/* ❌ Wrong — sizing breakpoints */
@media (min-width: 768px) {
  .grid { grid-template-columns: repeat(3, 1fr); }
}

/* ✅ Correct — use @container instead */
.grid-wrapper { container-type: inline-size; }

@container (min-width: 768px) {
  .grid { grid-template-columns: repeat(3, 1fr); }
}

Responsive Card Grid

A grid that adapts its column count based on the container width using @container queries.

svelte
<div class="cards-wrapper">
  <div class="cards">
    <Card.Root>...</Card.Root>
    <Card.Root>...</Card.Root>
    <Card.Root>...</Card.Root>
  </div>
</div>

<style>
  .cards-wrapper {
    container-type: inline-size;
  }

  .cards {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--dry-space-4);
  }

  @container (min-width: 480px) {
    .cards {
      grid-template-columns: repeat(2, 1fr);
    }
  }

  @container (min-width: 768px) {
    .cards {
      grid-template-columns: repeat(3, 1fr);
    }
  }
</style>

Auto-fill Grid

When you don't need specific breakpoints, auto-fill with minmax lets the browser decide how many columns fit.

css
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(240px, 100%), 1fr));
  gap: var(--dry-space-4);
}

Use named grid lines or template areas for page-level layout with sidebar, header, and footer.

css
.layout {
  display: grid;
  grid-template-columns: var(--sidebar-width, 260px) 1fr;
  grid-template-rows: auto 1fr auto;
  min-height: 100dvh;
}

.header { grid-column: 1 / -1; }
.footer { grid-column: 1 / -1; }

Centered Content with Full-bleed

A three-column grid trick that constrains content width while allowing full-bleed elements to break out.

css
.page {
  display: grid;
  grid-template-columns: 1fr min(var(--content-width, 72ch), 100%) 1fr;
}

.page > * {
  grid-column: 2;
}

.page > .full-bleed {
  grid-column: 1 / -1;
}

Vertical Stacking

Replace flexbox column layouts with a single-column grid. Use --dry-space-* tokens for consistent vertical rhythm.

css
/* ❌ Don't use flexbox */
.stack {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* ✅ Use grid */
.stack {
  display: grid;
  gap: var(--dry-space-4);
}

Spacing Scale

Use these tokens for all gap, padding, and margin values.

css
--dry-space-1   /* 4px */
--dry-space-2   /* 8px */
--dry-space-3   /* 12px */
--dry-space-4   /* 16px */
--dry-space-5   /* 20px */
--dry-space-6   /* 24px */
--dry-space-8   /* 32px */
--dry-space-10  /* 40px */
--dry-space-12  /* 48px */
--dry-space-16  /* 64px */

Lint Enforcement

These rules are enforced automatically by @dryui/lint — a Svelte preprocessor that runs during dev and build.