Astro components
Reusable components for building service pages and other content. Import these in MDX or Astro files.
PageHero
Full-width hero section with animated background shape. Used at the top of service pages and landing pages.
Import
import PageHero from '../../components/PageHero.astro'; Props
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | required | Main heading text |
subtitle | string | — | Optional subtitle below the heading |
colorScheme | string | 'fire' | Background colour: fire, sunshine, sorbet, gloaming, limestone |
shape | string | 'circle' | SVG shape: circle, threecircles, etc. |
shapeScale | number | 1 | Visual scale of the shape (1 = 100%, 2 = 200%) |
shapeRotation | number | 0 | Initial rotation angle in degrees |
shapeSize | string | '80vw' | Orbit container size (affects rotation radius) |
shapeTop | string | '50%' | Vertical position of orbit centre |
shapeLeft | string | '50%' | Horizontal position of orbit centre |
shapeOpacity | number | 1 | Shape opacity (0–1) |
shapeOrigin | string | 'center' | Rotation pivot point (CSS transform-origin, e.g. 'center', 'top left', '0 0') |
orbitRadius | string | '10%' | Distance from orbit centre. Set '0' to disable drift. |
orbitSpeed | number | 360 | Seconds for one full orbit. Set 0 to freeze orbit position. |
spinSpeed | number | 360 | Seconds for shape's own rotation. Set 0 to stop spinning. |
texture | string | '/images/ink2.jpg' | Path to texture overlay image |
textureOpacity | number | 0.05 | Texture opacity (0–1) |
Animation behaviour
The shape has two layers of animation:
- Orbit — The shape drifts around the orbit centre point (
shapeTop/shapeLeft), at a distance set byorbitRadius - Spin — The shape rotates around its own pivot point (
shapeOrigin)
Set speeds to 0 or radius to '0' to disable specific animations for a more static appearance.
Examples
Basic usage
<PageHero
title="Essence"
subtitle="Distilling organisational identity"
colorScheme="sunshine"
shape="threecircles"
/> Positioned shape with custom animation
<PageHero
title="Essence"
subtitle="Distilling organisational identity"
colorScheme="sunshine"
shape="threecircles"
shapeScale={2}
shapeRotation={10}
shapeLeft="100%"
shapeTop="50%"
orbitRadius="30%"
spinSpeed={360}
orbitSpeed={0}
/> Static shape (no animation)
<PageHero
title="About us"
colorScheme="fire"
shape="circle"
orbitRadius="0"
spinSpeed={0}
orbitSpeed={0}
/> Section
Flexible content section component. Supports single column, two-column with image, and numbered layouts.
Import
import Section from '../../components/Section.astro'; Props
| Prop | Type | Default | Description |
|---|---|---|---|
variant | 'default' | 'intro' | 'default' | Section style variant. 'intro' has larger heading and defaults to limestone-dark. |
colorScheme | ColorScheme | 'limestone' | Background: limestone, limestone-dark, fire, sorbet, sunshine, gloaming, gloaming-dark |
layout | 'single' | 'two-column' | 'single' | Layout mode |
image | string | — | Image filename from /src/assets/images/ (for two-column) |
imageAlt | string | '' | Alt text for the image |
imagePosition | 'left' | 'right' | 'right' | Which side the image appears on |
number | number | — | Large decorative number |
borderTop | 'solid' | 'paint' | 'torn' | — | Top border decoration style |
borderBottom | 'solid' | 'paint' | 'torn' | — | Bottom border decoration style |
Slots
| Slot | Description |
|---|---|
default | Main content (Markdown) |
media | Custom media content (used if no image prop) |
Examples
Simple section
<Section colorScheme="limestone-dark">
## The problem
Traditional brand projects tend to focus on visual identity...
</Section> Intro section
<Section variant="intro">
## Holistic content-centred solutions
Content is complex, and there are many aspects to planning...
</Section> The intro variant has larger headings and defaults to limestone-dark. Use for introduction sections after a PageHero.
Two-column with image
<Section layout="two-column" image="onion.png" imageAlt="Onion illustration">
## The solution
By recognising that organisational identity forms through...
</Section> Numbered section
<Section number={1} colorScheme="gloaming-dark">
## Beyond perception management
Our model isn't just about how an organisation is perceived...
</Section> Custom media via slot
<Section layout="two-column">
## Heading
Content here...
<video slot="media" src="/videos/demo.mp4" autoplay loop />
</Section> Decorative borders
<Section borderTop="torn" colorScheme="limestone">
## After the hero
Content with torn paper effect at top...
</Section> Notes
- Dark schemes (fire, gloaming, gloaming-dark) automatically get light text
- Two-column images extend 250% on desktop for dramatic effect
- Use the
mediaslot for custom media (video, multiple images, etc.) - Numbered sections show a large decorative number on the left
- Border styles: 'solid' (simple line), 'paint' (wavy edge), 'torn' (torn paper effect)
LatestGrid
A reusable “latest items” section used on the homepage. It renders the correct card component based on the type prop.
Import
import LatestGrid from '../../components/LatestGrid.astro'; Usage
<LatestGrid
title="Latest projects"
subtitle="Things we've been working on recently."
items={latestPortfolio}
type="portfolio"
viewAllHref="/portfolio"
/> ServiceCard
Used on the /services index to link to individual services. Typically fed from the services content collection.
Import
import ServiceCard from '../../components/ServiceCard.astro'; Usage
<ServiceCard
href="/services/strategy"
heading="Strategy"
description="Make content ecosystems work better."
buttonText="Explore"
icon={service.icon}
/> PortfolioCard
Card for portfolio/case study listings (used on /portfolio and in “Latest projects”).
Import
import PortfolioCard from '../../components/PortfolioCard.astro'; Usage
<PortfolioCard
title={item.data.title}
slug={item.slug}
featuredImage={item.data.featuredImage}
excerpt={item.data.excerpt}
headingLevel="h2"
serviceKeys={(item.data.services || []).map((service) => service.id)}
/> ResourceCard
Card for resource listings (used on /resources and in “Latest resources”).
Import
import ResourceCard from '../../components/ResourceCard.astro'; Usage
<ResourceCard
title={resource.data.title}
slug={resource.slug}
heroImage={resource.data.heroImage}
excerpt={resource.data.excerpt}
headingLevel="h2"
/> ThoughtCard
Card for thoughts/blog listings (used on /thoughts and in “Latest thoughts”).
Import
import ThoughtCard from '../../components/ThoughtCard.astro'; Usage
<ThoughtCard
title={thought.data.title}
slug={thought.slug}
heroImage={thought.data.heroImage}
excerpt={thought.data.excerpt}
headingLevel="h2"
/> DeviceScreenshot
Renders a screenshot inside a device frame (monitor/laptop/tablet/phone). Used inside DeviceComposite and elsewhere.
Import
import DeviceScreenshot from '../../components/DeviceScreenshot.astro'; Usage
<DeviceScreenshot device="tablet" screenshot="demo.png" alt="Demo screenshot" /> DeviceComposite
Arranges multiple device screenshots into a composite layout (e.g. monitor + laptop + tablet + phone).
Import
import DeviceComposite from '../../components/DeviceComposite.astro'; Usage
<DeviceComposite
monitorScreenshot="screenshot-desktop.png"
laptopScreenshot="screenshot-laptop.png"
tabletScreenshot="screenshot-tablet.png"
phoneScreenshot="screenshot-phone.png"
alt="Product screenshots"
width="80vw"
/> Clients
Renders the client logo grid from the clients content collection.
Import
import Clients from '../../components/Clients.astro'; Usage
<Clients /> HowWeCanHelp
Homepage section that lists services from the services content collection in a fixed order.
Import
import HowWeCanHelp from '../../components/HowWeCanHelp.astro'; Usage
<HowWeCanHelp /> QuoteBlock
A full-width quote section with optional decorative borders and background colour token.
Import
import QuoteBlock from '../../components/QuoteBlock.astro'; Usage
<QuoteBlock
quote="Groundbreaking, strategic, and forward-thinking…"
attribution="James Wood, former Head of Content, Internet Society"
background="fire-extra-dark"
borderBottom="paint"
/> ProductFeature
A marketing block built on Section + DeviceScreenshot, used to promote products/tools.
Import
import ProductFeature from '../../components/ProductFeature.astro'; Usage
<ProductFeature
title="Content Health Check"
content="<p>...</p>"
buttonText="Get a health check"
buttonUrl="https://contenthealthcheck.com"
screenshot="content-health-check-screenshot.png"
screenshotAlt="Content Health Check tool"
colorScheme="limestone-dark"
imagePosition="left"
backgroundTexture="watercolour"
/> Subscribe
A full-width newsletter sign-up section with a decorative top border and a device illustration.
Import
import Subscribe from '../../components/Subscribe.astro'; Usage
<Subscribe /> Border
Decorative border used by Section, QuoteBlock, and Subscribe.
Import
import Border from '../../components/Border.astro'; Usage
<Border style="paint" position="top" color="var(--fire)" /> Portfolio case studies
Case studies are stored as Markdown files in the portfolio content collection and rendered with PortfolioLayout and PortfolioCard. This section covers how to add a new case study and tag it with services.
Location
Add or edit files in src/content/portfolio/. Each file becomes a page at /portfolio/<slug>/ and an item on the portfolio index.
Frontmatter
Use this frontmatter shape:
---
title: "Content strategy foundations for Brooke"
subtitle: "Joined-up content strategy foundations for Brooke"
date: 2025-01-17
excerpt: "Short summary used on the portfolio index."
featuredImage: "chang-qing-8oPubUm97Cc-unsplash-400x284.jpg"
services:
- Essence
- Strategy
---
## The challenge
Body content here... titleandsubtitlefeed the hero and index card.dateis used to sort case studies (newest first).excerptappears under the title on the index card.featuredImageis the thumbnail on the index grid.servicesis an array of service names (e.g.Essence,Strategy,System,Product,Know-how).
Images
Place case study thumbnails in src/assets/images/ and reference them by filename via featuredImage. PortfolioCard uses the shared responsive image system (getImage + Image) so new thumbnails automatically benefit from optimisation.
Services and filtering
The services array is used in two places:
- On
/portfolio/to filter case studies by service (All, Essence, Strategy, System, Product, Know-how). - On service pages to surface related case studies, by querying
getCollection('portfolio')and filtering whereservicesincludes the current service.
A case study can have more than one service. It will appear under every relevant filter, and in multiple "related case studies" lists where appropriate.