Back to Airbnb Clone

Documentation

guide

Airbnb Clone: Component Architecture Guide

Welcome to the Airbnb UK homepage clone. This guide walks you through what we built, how it all fits together, and why the architecture matters. If you've never worked with a component-based frontend before, don't worry — this guide is written with you in mind.


What Is This Project?

This is a pixel-perfect recreation of the Airbnb UK homepage (airbnb.co.uk), built entirely from scratch using modern web technologies. The frontend is React with TypeScript, the backend is Go with GraphQL, and the whole thing is tested with automated screenshot comparisons.

But the real story isn't just "we cloned a website." The real story is how we built it — using a component architecture that makes the entire UI modular, testable, and swappable. Every button, every card, every section of the page is its own self-contained piece. You can rearrange them, restyle them, or drop them into a completely different project.


The Component System: Atomic Design

We use a pattern called Atomic Design, which organises UI components into five layers. Think of it like chemistry: you start with the smallest possible pieces, and you combine them into increasingly complex structures.

Atoms (27 components)

These are the smallest building blocks — things that can't be broken down any further. A logo, a badge, a single icon, a star rating. On their own they don't do much, but everything else is built from them.

Logo component

The logo above is a single atom. It's just an SVG icon and a wordmark, styled with CSS. But because it's isolated as its own component, we can change the brand colour in one place and it updates everywhere — the header, the footer, any page that uses it.

Badge component

Same idea with badges. This "Guest favourite" badge appears on listing cards, but it's defined once and reused wherever it's needed.

Molecules (17 components)

Molecules are small groups of atoms working together. A search bar is a molecule — it combines an input field, some icons, and a button into something that feels like a single interactive element.

Search bar molecule

The search bar above combines several atoms (icons, text, a button) into a cohesive unit. It handles its own layout and spacing internally, so wherever you place it on the page, it just works.

Navigation tabs

Navigation tabs are another molecule. Each tab is essentially an atom (a clickable label), but the molecule handles the switching behaviour and the active state indicator.

Booking card

The booking card is one of the more complex molecules. It brings together price displays, date selectors, guest counters, and a reserve button into a single reusable widget. The component handles all the internal layout, but the data it displays comes from props passed in by its parent.

Photo grid

The photo grid arranges images in an asymmetric layout — one large hero image on the left, four smaller ones on the right. This pattern appears on room detail pages and is reusable anywhere you need a gallery-style layout.

Review summary

The review summary molecule combines a star rating, review count, and category breakdowns into a compact overview. It's designed to give users a quick snapshot before they dive into individual reviews.

User menu

The user menu is a compact molecule that sits in the header. It combines a hamburger icon and a user avatar into a dropdown trigger.

Organisms (14 components)

Organisms are larger sections of the page — things like the header, the footer, or an entire search section. They're built by composing molecules and atoms together.

Header organism

The header organism combines the logo atom, navigation tabs molecule, search bar molecule, and user menu molecule into the full top bar you see on every page. Each piece is independent, but the organism defines how they sit together.

Search section

The search section is the prominent area below the header where users type their search. It wraps the search bar molecule in a styled container with background colours and spacing.

Inspiration section

This organism powers the "Inspiration for future getaways" section. It combines tab navigation with a grid of destination cards, and the data comes from the GraphQL backend — the component just renders whatever it receives.

Listing card

The listing card organism wraps an image carousel, location text, pricing, and a rating badge into a single card. On the homepage, you'd see a grid of these. Each card is the same component, just rendered with different data.

Listing info

The listing info organism appears on room detail pages. It shows the property title, host information, key features, and amenities — all composed from smaller atoms and molecules.

Reviews section

The reviews section organism combines the review summary molecule with individual review cards, laid out in a grid. It handles pagination and the overall section layout.

Things to know

This organism presents house rules, safety information, and cancellation policies in a three-column layout. Each column is built from the same underlying atoms but populated with different content.

Footer organism

The footer is a large organism with multiple columns of links, organised by category (Support, Hosting, Airbnb), plus legal text and language/currency selectors at the bottom.

Templates (2 components)

Templates define the overall page layout — where the header goes, where the main content area lives, where the footer sits. They don't contain any real content themselves; they just provide the structure that organisms slot into.

We have two templates: HomeTemplate for the homepage layout, and RoomTemplate for property detail pages.

Pages (3 components)

Pages are the final layer. They wire up data fetching (GraphQL queries via Apollo Client) and pass real data down through templates, into organisms, into molecules, into atoms. A page component is the glue between your backend data and your visual components.

Full homepage

The homepage above is assembled entirely from the components described in this guide. The header organism at the top, the search section, the inspiration grid, and the footer — all composed together through a template.

Room detail page

The room detail page uses the same header and footer organisms, but swaps in different organisms for the main content: a photo grid, listing info, booking card, reviews section, and things-to-know.


The Full Picture

Here's how the actual homepage looks when everything comes together:

Homepage at 1440x900

And here's the full-page version showing everything from top to bottom:

Full homepage scroll

Every pixel you see on that page is rendered by one of the 63 components in our library. Nothing is hardcoded in the page itself — it's all composition.


Why This Matters

Everything is isolated and testable

Each of the 63 components has its own file, its own CSS module (so styles never leak between components), and its own Storybook story (so you can view and interact with it in isolation). We have 79 automated tests that verify component behaviour without needing a running server.

Reskinning is trivial

Because all visual styling flows through CSS custom properties (design tokens), you can completely change the look of the entire application by editing a single file: frontend/src/styles/variables.css. Change the brand colour from Airbnb red to blue, adjust the border radius, swap the font — and every single component updates automatically. The TypeScript interfaces don't change. The tests still pass. The data layer is untouched.

This means you could take this same component library and create a completely different brand identity in an afternoon, without touching a single line of component logic.

Storybook lets you see everything

Every component has a Storybook story, which means you can browse the entire component library in your browser at http://localhost:6006. You can see each component in isolation, inspect its props, and understand how it works before you use it. This is invaluable for designers reviewing implementations, for new developers learning the codebase, and for QA teams checking visual consistency.

The data layer is completely separate

Components don't fetch their own data — they receive it through props. The GraphQL queries live in the page components, and data flows downward through the component tree. This means you can swap out the backend entirely (switch from GraphQL to REST, or from Go to Node) without changing a single component.


How to Run It

You need three things running to see everything:

The backend serves the GraphQL API that provides destination data, listings, and reviews:

bash
cd backend && go run ./cmd/server
# Now running on http://localhost:8080

The frontend is the React application that renders the actual pages:

bash
cd frontend && npm install && npm run dev
# Now running on http://localhost:5173

Storybook lets you browse every component in isolation:

bash
cd frontend && npm run storybook
# Now running on http://localhost:6006

Once all three are running, open http://localhost:5173 to see the full application, or http://localhost:6006 to explore the component library.


Project Structure

shell
frontend/
  src/
    components/
      atoms/          27 components (Logo, Badge, StarRating, Icons...)
      molecules/      17 components (SearchBar, BookingCard, NavTabs...)
      organisms/      14 components (Header, Footer, ListingCard...)
      templates/       2 components (HomeTemplate, RoomTemplate)
      pages/           3 components (HomePage, RoomDetailPage, MockPage)
    styles/
      variables.css   Design tokens (colours, spacing, shadows, radii)
      global.css      Base reset and typography
  .storybook/         Storybook configuration

backend/
  cmd/server/         Entry point
  internal/
    domain/           Business entities
    ports/            Interface definitions
    application/      Use cases
    adapters/         GraphQL resolvers, in-memory repos

e2e/
  capture-comparison.ts   Automated screenshot capture script


Capturing Screenshots

The screenshots in this guide were captured automatically using a Playwright script. If you want to regenerate them (for example, after making visual changes), make sure all three servers are running and then:

bash
cd e2e && npx tsx capture-comparison.ts

This captures 20 screenshots covering the full homepage plus individual components from Storybook, and saves them to docs/screenshots/.


Key Takeaways

This project demonstrates that a production-quality UI like Airbnb's can be decomposed into a library of 63 independent, composable components. Each component is isolated, tested, and documented in Storybook. The visual design is controlled entirely through CSS design tokens, making the whole system reskinnable without touching component logic. And because the data layer is separated from the presentation layer, the same component library could power completely different applications.

The architecture isn't just academic — it's how modern frontend teams ship at scale. Small, focused components that compose into complex UIs, with automated testing at every level.

© 2026 Jonathan Leahy · v0.9.1