Contact Us

Content Composition Showcase

LayoutSection + sibling Heading composition patterns and Fragment rendering.

Composition Patterns

Visible Heading with Intro

Section intro text introduces the body content.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec eu nulla ut augue malesuada luctus.

Morbi suscipit sapien non ligula pretium, sed interdum justo scelerisque.

Visible intro with hidden semantic heading.

Using LayoutSection `label` provides an accessible name via `aria-label` on the `<section>` element, replacing the previous sr-only heading pattern.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec eu nulla ut augue malesuada luctus.

Morbi suscipit sapien non ligula pretium, sed interdum justo scelerisque.

Centered Content

Checks centered alignment and inverted token contrast.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec eu nulla ut augue malesuada luctus.

Morbi suscipit sapien non ligula pretium, sed interdum justo scelerisque.

Show code
{/* Visible heading with intro */}
<LayoutSection verticalPadding="xl">
  <Heading level={3}>Visible Heading with Intro</Heading>
  <p class="mt-sm">Section intro text introduces the body content.</p>
  <p>Body content here.</p>
</LayoutSection>

{/* Screen-reader-only heading via LayoutSection label */}
<LayoutSection background="soft" verticalPadding="xl" label="Screen Reader Only Heading">
  <p>Visible intro with hidden semantic heading.</p>
  <p>Body content here.</p>
</LayoutSection>

{/* Centered contrast */}
<LayoutSection background="contrast" verticalPadding="xl">
  <Heading level={3} class="text-center">Centered Content</Heading>
  <p class="mt-sm text-center">Checks centered alignment.</p>
  <p class="text-center">Body content here.</p>
</LayoutSection>

Fragment

This page validates the getFragment() utility by loading and rendering a fragment from the fragments collection.

Fragment Demo

This fragment is used by the showcase to validate getFragment() integration.

Show code
import { getFragment } from "@/lib/content/fragments";

const fragment = await getFragment("demo-fragment");
const { Content } = fragment;

<LayoutSection background="soft" verticalPadding="sm" label="Fragment demo">
  <Content />
</LayoutSection>

Pullquote

Decorative pull quote with optional citation. Visually distinct from standard prose blockquotes.

SVG Quote (default)

Design is not just what it looks like. Design is how it works.

Text Quote

Simplicity is the ultimate sophistication.

No Quote Decoration (with citation)

Less, but better.

— Dieter Rams
Show code
{/* SVG quote icon (default) */}
<Pullquote>
  <p>Design is not just what it looks like. Design is how it works.</p>
</Pullquote>

{/* Text quote character */}
<Pullquote quoteStyle="text">
  <p>Simplicity is the ultimate sophistication.</p>
</Pullquote>

{/* No quote decoration (with citation) */}
<Pullquote quoteStyle="none" citation="Dieter Rams">
  <p>Less, but better.</p>
</Pullquote>

TimeToRead

Reading time display with icon. Consumes the readingTimeMinutes value from the remark-reading-time plugin. The values below are placeholder demonstrations.

Default label

5 min read

Custom label

3 minute read

Undefined (renders nothing)

← nothing rendered above

Show code
---
import TimeToRead from "@core/components/ui/TimeToRead.astro";

// In a content page, get the reading time from the remark plugin:
const { remarkPluginFrontmatter } = await render(entry);
const readingTimeMinutes = remarkPluginFrontmatter?.readingTimeMinutes;
---

{/* Typical usage on an article page */}
{entry.data.readingTime && (
  <TimeToRead minutes={readingTimeMinutes} />
)}

{/* Custom label */}
<TimeToRead minutes={readingTimeMinutes} label="{n} minute read" />

Columns

Generic N-column CSS grid layout with three column patterns: equal, asymmetric, and auto-fit.

Equal Columns (3)

Column 1

Column 2

Column 3

Asymmetric (2fr 1fr)

Wide column (2fr)

Narrow (1fr)

Auto-fit

Card 1

Card 2

Card 3

Card 4

No Collapse

Always 3 columns

Even on mobile

No collapse

Show code
{/* Equal columns — collapses below md (default) */}
<Columns columns={3}>
  <div>Column 1</div>
  <div>Column 2</div>
  <div>Column 3</div>
</Columns>

{/* Asymmetric — also collapses below md by default */}
<Columns columns="2fr 1fr">
  <div>Wide column</div>
  <div>Narrow sidebar</div>
</Columns>

{/* Auto-fit responsive grid */}
<Columns columns={{ count: "auto-fit", min: "12rem" }}>
  <div>Card 1</div>
  <div>Card 2</div>
</Columns>

{/* Never collapse */}
<Columns columns={3} collapseBelow="none">
  <div>Always visible</div>
  <div>Even on mobile</div>
  <div>No collapse</div>
</Columns>

{/* Collapse below lg instead of md */}
<Columns columns={2} collapseBelow="lg">
  <div>Left</div>
  <div>Right</div>
</Columns>

MediaText

Content-level split layout pairing an image with text. Supports reverse order and split ratio variants.

Default (image left)

Placeholder image

Image and Text

Text content sits alongside the image. The default split is equal (1:1). On mobile, the layout stacks with the image above the text.

Reversed (image right)

Placeholder image

Reversed Layout

The image moves to the right side. On mobile, the image still appears above the text for consistent reading flow.

Wide Content Split

Placeholder image

More Text Space

The content column is wider than the image column (3:2 ratio). Vertical alignment is set to "start" so content aligns to the top.

Show code
{/* Default: image left, equal split */}
<MediaText image={{ src: "/images/photo.jpg", alt: "Description" }}>
  <h3>Heading</h3>
  <p>Text content alongside the image.</p>
</MediaText>

{/* Reversed: image right */}
<MediaText image={{ src: "/images/photo.jpg", alt: "Description" }} reverse>
  <h3>Reversed</h3>
  <p>Image on the right side.</p>
</MediaText>

{/* Wide content, top-aligned */}
<MediaText
  image={{ src: "/images/photo.jpg", alt: "Description" }}
  split="wide-content"
  verticalAlign="start"
>
  <h3>Wide Content</h3>
  <p>Content column is wider.</p>
</MediaText>

Table

Responsive styled table wrapper with scroll and stack mobile modes.

Scroll Mode (default)

Name Role Department Status Location
Alice Johnson Developer Engineering Active Remote
Bob Smith Designer Product Active New York
Carol Davis Manager Operations On Leave London

Stack Mode

Name Role Status
Alice Johnson Developer Active
Bob Smith Designer Active
Show code
{/* Scroll mode (default) with striped rows */}
<Table striped>
  <table>
    <thead>
      <tr><th>Name</th><th>Role</th><th>Status</th></tr>
    </thead>
    <tbody>
      <tr><td>Alice</td><td>Developer</td><td>Active</td></tr>
    </tbody>
  </table>
</Table>

{/* Stack mode — cells become blocks on mobile */}
<Table responsive="stack" hoverable>
  <table>
    <thead>
      <tr><th>Name</th><th>Role</th><th>Status</th></tr>
    </thead>
    <tbody>
      <tr>
        <td data-label="Name">Alice</td>
        <td data-label="Role">Developer</td>
        <td data-label="Status">Active</td>
      </tr>
    </tbody>
  </table>
</Table>

Cover

Background image with overlay and positioned content. Overlay opacity and color are configurable.

Default (centered)

Placeholder background

Cover Heading

Overlay content with readable text over the background image.

End Position, Higher Opacity

Placeholder background

Bottom Content

Content positioned at the bottom of the cover area.

Show code
{/* Default: centered content */}
<Cover image={{ src: "/images/hero.jpg", alt: "Background" }}>
  <h2>Cover Heading</h2>
  <p>Overlay content.</p>
</Cover>

{/* Bottom-aligned, higher opacity */}
<Cover
  image={{ src: "/images/hero.jpg", alt: "Background" }}
  contentPosition="end"
  overlayOpacity={0.7}
  minHeight="20rem"
>
  <h2>Bottom Content</h2>
</Cover>

Timeline

Vertical timeline for project histories, about pages, and changelogs.

  1. Project Started

    Initial planning and requirements gathering phase.

  2. Design Phase

    Wireframes, visual design, and component library established.

  3. Development

    Core implementation with iterative review and testing.

  4. Launch

    Site launched successfully with all milestones complete.

Show code
<Timeline>
  <TimelineItem title="Project Started" date="January 2026">
    <p>Initial planning and requirements gathering.</p>
  </TimelineItem>
  <TimelineItem title="Design Phase" date="February 2026">
    <p>Wireframes and visual design completed.</p>
  </TimelineItem>
  <TimelineItem title="Launch" date="March 2026">
    <p>Site launched successfully.</p>
  </TimelineItem>
</Timeline>

Search

Search across pages and articles. Use arrow keys to navigate results.

Search across pages and articles.

Loading search...

Search is unavailable. Please try again later.

    No results for ""

    Try different keywords or fewer words.