025
AI ready Refreshed

Bookshop Template

£29 View live demo or the whole Vault, £79.20

Includes the original v1 design as a separate download.

A six-page site for an independent bookshop where every book looks like a real paperback: a shelf of mixed spines you pull to open the book on the table below, and a front-table hero whose colour changes with the featured cover. Grainger Street Books in Newcastle is the worked example.

ScrollTrigger Lenis intermediate
14 more details
3d-transformsclick-toggletouch-dragkeyboard-navigationfocus-managementclip-pathview-transitionsfiltercontainer-queriesscroll-revealstaggerinteractive-mapform-validationprogressive-enhancement

Updated

About this template

A complete six-page site for an independent bookshop that looks like a shop full of real books. Every cover is its own artwork with the title and author set over it in type, in the style of its imprint: a Caslon literary novel, a Bodoni translated classic, a heavy grotesk debut, a children's book in big italic. Each one is drawn as an object, with a page block on the fore-edge, a hinge at the spine, a soft sheen and a contact shadow, so a grid of them reads as a table of paperbacks.

Read the full template overview

The signature is the shelf. The shelf is a single photograph of sixteen paperbacks cut into a layer per book, each spine designed to match its cover, with the title on a small paper label as you point at a book. Pull one, by click, keyboard or by dragging it down with a mouse, and the book tips out and opens on the table beneath it: the real cover on one side, the bookseller's note, price and a hold button on the other. The home page carries nine spines, the Books page all fourteen with shelf filters, and the book page its neighbours.

The home hero is the front table: the featured book large, two more lying under it, a photograph of the shop beside it, and a field the colour of the featured cover. Turn the table and the field changes to the next book's colour, with text colours measured for each. The shop's own deep blue runs the nav, the footer and the club and visit pages.

Around that sit the pages a real shop needs: a book page with a cover you can turn over and a reserve form, an events list with date blocks and cover thumbnails, a club page with a library date-due slip you stamp to save a seat, and a visit page with today's hours, a live open-now line and a real street map with walking routes. Swap in your own covers (any flat artwork), titles and photographs; the pages are plain HTML with no build step.

Bookshop Template - website template preview

What's included

12 items
  • Six plain HTML pages: home, this season's top picks, a book page, events, club and visit, with a crossfade between pages and a cover that carries into the book page where browsers support it
  • The spine pull: a shelf of designed book spines that tip out and open on the table below, by click, Enter or a mouse drag; one book open at a time, Escape or Put it back returns it
  • Sixteen books drawn as real paperbacks: cover art with HTML titles in eight imprint styles, the book's own photographed spine and a photographed page block, consistent in every browser
  • A real shelf from one photograph: sixteen paperbacks cut into layers over a painted plate, each spine its book's own design with its title on a paper label on hover or focus, so pulling a book lifts the photographed book out of its slot
  • Turn the table: the home hero's featured book changes with buttons, arrow keys or a swipe, and the whole field takes the colour of its cover
  • Handwritten shelf-talker cards from the booksellers that tip in, swing on their clip and write their note on, on the hero book, the shelves and the grid
  • Books page with shelf filters that sort both the spine wall and the grid of covers, and links that open a given book on arrival
  • Book page with a cover you can turn over to read the back, plus a reserve form
  • Club page with a library date-due slip: the year's meetings stamped READ, and a button that stamps HELD on the next one
  • Visit page with today's row marked in the hours table, a live open-now line in shop time, and a MapLibre street map with two routed walking lines
  • Designed phone menu: a blue sheet with the pages set large in Caslon, Escape and scrim to close, focus moved in and returned
  • Bundled WebP images: fourteen generated cover artworks, one generated shelf photograph cut into layers, shop photographs from Pexels, and self-hosted subset fonts

Perfect for

5 use cases
  • Independent bookshops, new or secondhand
  • Small presses and publishers presenting a list
  • Record shops, print and poster shops with a curated stock
  • Wine merchants, delis and other shops that sell a chosen shelf
  • Literary festivals, reading rooms and libraries with an events programme

How it works

5 sections

Six standalone pages

Every page is an ordinary HTML file sharing one stylesheet and one script. Each feature looks for its own data- hook and does nothing when the markup is missing, so a section or a whole page can be deleted without touching the script. Navigation is a normal page load with a CSS cross-document view transition where the browser supports one.

Books as objects

Each cover is a flat artwork image with the title, author and imprint set over it in HTML, so the type stays sharp and editable. Off the shelf, a book is drawn as one flat layer: the cover, its own photographed spine cut from the shelf photo, and a photographed page block, so it renders the same in every browser and matches the book on the shelf.

The shelf and the table

The shelf is one photograph cut into a layer per book over a plate where every book's place is an empty slot. Each book is a real button outlined to its own shape and controls the spread on the table below. Opening one lifts it out of its slot and closes the last; Escape or Put it back returns focus to the spine. With a mouse, a book can also be dragged up off the shelf; on touch a tap does it, so the page still scrolls.

Live shop details

Opening hours sit in one object at the top of the script. They drive the open-now line in the nav, hero and visit page, and mark today's row in the hours table, all in the shop's own time zone. The visit map uses MapLibre on OpenFreeMap tiles with walking routes stored as coordinates.

Without JavaScript or with reduced motion

Without JavaScript every book's spread reads in full under its shelf like a printed catalogue, only the first featured book shows, and the footer carries every page link. Under reduced motion nothing travels, but the shelf, the table turn, the cover flip and the stamp all still work, as instant changes.

Plugins ScrollTrigger
Difficulty Intermediate
Smooth scroll Lenis integration
Includes HTML + JS + CSS source, documentation, AI setup prompt, lifetime updates

Lighthouse, as measured

Google Lighthouse on this template's demo (6 pages, lowest score shown), from the latest scan. A measurement of the demo as shipped, not a promise for your page.

Accessibility
100
Best practices
100

No performance score, on purpose. That figure depends on how you deploy: your server's compression and caching, your CDN, the connection and the device doing the test, none of which the code controls. The same page can score very differently on two consecutive runs, so measure it where it will live.

Questions about this template

Is this only for bookshops?

No. The design is a shelf of uniform designed objects with a title, a maker, one line from a person and a price, on fields of one colour. A small press can use it for a season's list, a record or print shop for its racks, and a wine merchant or deli for a chosen shelf. Grainger Street Books in Newcastle is only the worked example.

Can I use real book covers?

Yes. Each cover is an image with its title and author set over it in HTML, so you can drop in a publisher's cover image and delete the type layer, or keep our approach: flat artwork plus live text in one of seven imprint styles. The bundled artworks are generated for the template and contain no text, so they are free to reuse with your own titles.

How do I add a book to the shelf?

The shelf is one photograph of sixteen paperbacks cut into layers, so a new spot needs a book in the photo: retitle any of the sixteen by changing its label, its spread on the table and its tile on the Books page. For a different shelf, the README gives the photo prompt and the cutting script that turns any shelf photo into a plate and one layer per book.

Do the reserve, club and Ask us forms send anything?

No, they are an unwired static front end. The reserve form collects a name and an email or phone, the Ask us form a name, email and message, and the club button only stamps the slip on the page. Point the forms at Formspree, Netlify Forms or your shop system's endpoint and remove the one line in the script that stops them submitting.

Can I sell books through it?

It has no basket or checkout, by design: it is a browsing, events and reserve-a-copy site, which is what many independent shops want. You can point each book's button at your shop on Bookshop.org, your own online store, or a payment link, in place of the hold and reserve buttons.

Can I change the blue, or use two colours?

The shop colour is one --blue token at the top of the stylesheet: nav, footer, club and visit fields, stamps, map routes and buttons. The home hero instead takes each featured book's colour from a data-field attribute on its slide, with the text colour beside it; pick colours that keep 4.5:1 against that text. Spine colours are set per book on its style attribute.

How do I set my own opening hours and map?

Hours live in one HOURS object at the top of the script and in the hours table on the visit page, with the time zone beside them. The map pin, the two walking routes and their start labels are coordinate lists in the same place; route your own with the free OpenStreetMap router and paste the lines in. The map needs no API key.

Paid template

Purchase to unlock the code.

Buying Bookshop Template opens the HTML, CSS and JavaScript source, the full documentation, an AI setup prompt for your editor, and every update we ship to it. Standard license: unlimited personal and commercial projects. Every paid product is tested for desktop and mobile layouts, reduced-motion handling, animation cleanup and keyboard controls wherever there is something to operate.

£29 Standard license, unlimited projects

Browse free effects

Or the whole library: the Vault, £79.20, one payment.

Documentation

Quick Start

  1. Unzip and open index.html in a browser, or serve the folder with any static server (npx serve .).
  2. The pages are plain HTML files: index.html (home), books.html (This season's top picks, "Top picks" in the nav), book.html (one book), events.html, club.html and visit.html.
  3. Every page shares assets/style.css and assets/script.js. There is no build step.
  4. Deploy the folder as it is to any static host.

Using It With Your Own Design

  • Shop colour: one --blue token at the top of assets/style.css runs the nav, footer, the club and visit fields, stamps, buttons and map routes. Keep white text at 4.5:1 or better on it; the measured pairs are in the stylesheet's first comment.
  • Book colours: each book carries its own colours. On covers and spines they are --bg and --ink on the element's style; on the home hero each slide has data-field, data-field-ink and data-field-soft, which the script applies when the table turns. The bundled values were measured at 4.5:1 or better.
  • A section becomes a blue field with the class field and data-ground="blue"; everything inside it takes its colours from that.
  • Type: Libre Caslon Display (headings), Libre Caslon Text (reading) and League Spartan (small labels), with Bodoni Moda and Archivo for cover and spine type and Caveat for the shelf-talkers. All are self-hosted in assets/fonts/ (the latin woff2 files Google Fonts serves, declared at the top of assets/style.css), so the site makes no font requests to Google. All six families are under the SIL Open Font License 1.1; the copyright notices and licence text are in assets/fonts/OFL.txt. Swap a face by replacing its file and its @font-face block, then --font-display, --font-body and --font-label.

Pages and Configuration

Page Sections Hands-on piece
Home Front-table hero with a shop photograph, four on the table, the front shelf, next event and club, find us Featured book with field colour, nine-spine shelf
Top picks (books.html) Title and shelf filters, the photographed shelf of sixteen books, wrapping at the counter, every book by shelf Spine pull, filters
Book Cover and reserve form, the bookseller's note, three related books, its neighbours on the shelf Turn the cover over, reserve form, five-spine shelf
Events Photograph header, the season by month, Thursdays field, past evenings Event rows with cover thumbnails
Club Date-due slip, this month's book, two photographs, monthly subscriptions Stamp the slip to save a seat
Visit Address and shopfront, hours and notes, walking routes, Ask us form Routes on a real map, open-now line, form

Every feature looks for its own data- hook and does nothing when the markup is missing, so you can delete a section, or a page and its nav links, without editing the script. Links between pages are ordinary page loads with a short crossfade (@view-transition in the stylesheet). The Low Water cover carries a view-transition-name on the home hero, the Books grid and the book page, so it travels into book.html where the browser supports it.

A book

A book appears up to three times, each a short block of markup you can copy:

  • Spine (button.spine inside ul.shelf__books): the book's photographed layer, a hit outline so only the book itself takes the pointer, a visually hidden name, and data-label/data-by for the paper label. aria-controls names the spread it opens.
  • Spread (article.spread inside div.table, the same shelf): the cover, shelf and format, title, author, the bookseller's note, their name, price and a button. Its id matches the spine's aria-controls.
  • Tile (li.tile in a ul.tiles grid): cover on paper with an italic caption. data-grid-item is its shelf, used by the filters.

A cover (div.cover) is the same markup everywhere: an img.cover__art (flat artwork, 2:3, no text), then the author, title, an optional translator line and the imprint mark. cover--sA to cover--sH choose one of eight type treatments (literary serif, Bodoni capitals, heavy grotesk, stacked capitals, centred italic, a classics band, big italic), and --bg/--ink on its style set the board colour behind the art and the type colour. Shared layers draw the fore-edge page block, the spine hinge, the sheen and the shadow. It is sized by its container, so place it in anything with a width. To use a publisher's real cover image instead, put it in cover__art and delete the cover__face text.

Books off the shelf (.book)

Every book shown away from the shelf (hero, grid tiles, book page, the table spread) is drawn flat, with no preserve-3d, so every engine, iOS Safari included, renders it the same: the front cover, then the book's own photographed spine (assets/img/spines/<name>.webp, cropped from the shelf photo by the cutting script) skewed on the left, and a photographed page block (assets/img/spines/pages.webp) on top. A book pulled off the shelf therefore shows the identical spine in the spread. --r (the spine's width over its height, measured from the photo) sets the thickness; --vx/--vy set how much spine and top show and --ay/--ax are the matching skew angles. .book--r turns a book the other way to show its fore-edge.

The shelf is one photograph

Every shelf on the site is the same photograph of sixteen blank paperbacks, cut into layers: assets/img/shelf/plate.webp is the photo with each book's place painted as an empty slot (wall carried down, darkening to the shelf, shadowed by the neighbours), and assets/img/shelf/<name>.webp is one transparent cut-out per book, laid back over the plate in exactly its place. With every layer in place it is the photograph; pulling a book lifts its layer and shows the slot behind. The spines carry their photographed art alone. Each spine is a button named "Title by Author" for screen readers, and the book's title and author appear on a small paper label above it (.shelf__label) on hover, keyboard focus or a tap; the text comes from the button's data-label and data-by.

The stage keeps the photo's aspect and scales as one unit. Below about 760px it keeps a minimum width and the strip scrolls sideways. A crop shows part of the photograph (the book page uses one): any book inside the crop that is not on that page's list stands there as part of the picture.

To use your own shelf photo

  1. Photograph (or generate) one shelf of real-looking paperbacks, lit from one side, slightly from above,. The photo used here was generated in two passes: first a shelf of sixteen blank paperbacks, then, using that picture as the reference so the books keep their places, heights and leans, the same shelf with each spine designed. The second pass used this prompt:

    Photograph of one shelf in an independent bookshop, sixteen paperback books with spines facing the camera, each spine printed with its own graphic design like real publishers' paperbacks, but with absolutely no text, letters, numbers or logos anywhere. Left to right:

    1. mustard yellow spine with a teal-blue water band across the lower third and a tiny cream ferry shape on it;
    2. pale cream spine with fine straw-coloured grass blades rising from the bottom edge;
    3. spine split in two: pastel pink upper half, turquoise water lower half, a thin white line between;
    4. pale green spine with small scattered red tomatoes and green bean pods;
    5. watercolour spine, pale grey-blue sky at the top fading into sage-green and mud-brown estuary wash at the bottom;
    6. near-black deep teal spine with a small warm amber lamp glow near the top;
    7. off-white spine with black pine-tree silhouettes along the bottom and a tiny red house;
    8. light grey spine with a small bright yellow sun circle near the top and three short blue diagonal rain marks below it;
    9. white paper spine with a loose black ink scribble line and a soft orange watercolour patch;
    10. cream spine with a fine black ink line drawing of a bridge arch and a cobalt blue band at the foot;
    11. deep brick-red spine with a black-and-white vintage photograph strip panel across the middle;
    12. tan spine with a mustard knitted-wool texture panel and a small blue darning stitch patch;
    13. spine of horizontal wavy colour bands: violet, cream, blue, green, orange, pink;
    14. warm sunset orange-pink spine with red-and-white lighthouse stripes near the bottom;
    15. mustard spine with a simple cream soup bowl shape near the bottom;
    16. slate grey spine with a thin pair of railway lines running down it. Leave a calm plain area in the middle of every spine (where a title will be added later). Real paperback details: soft creases near the spine edges, scuffed corners, cream page-block tops, shadows in the gaps. Natural colour, realistic printed card and paper texture, documentary photo, no text anywhere.
  2. Save it as assets/img-src/shelf/shelf-e.jpg and trace one polygon per book in assets/img-src/shelf/polys.json: the front face, the cream page block on top and any side face you can see, in source pixels. Books nearer the middle of the picture sit in front of their neighbours. Add each spine's front face as face (left and right at its foot, top, bottom and its lean in degrees).

  3. Run python3 assets/img-src/shelf/cut-shelf.py (Pillow only). It writes the plate, the layers and assets/img/shelf/shelf.json with each layer's box, hit outline and face.

  4. Update each book's position in the shelf markup (.shelf__slot style: left, top, width and height as percentages of the photo) from shelf.json.

Shelf-talkers ([data-talker])

The handwritten cards booksellers clip to shelves. Each is real text: two .talker__line spans, a pencil underline and the bookseller's name. The script tips the card in, lets it swing on its clip, then writes the note on line by line with clip-path and draws the underline. On the home hero each featured book carries its own card, and turning the table lifts the old card off before the next one writes on. On shelves, a card's data-for names the spine it hangs below; the script lines it up under that spine. Under reduced motion, or without JavaScript, the cards are simply there, fully written. The handwriting face is Caveat.

The shelf ([data-shelf])

Any element with data-shelf that contains spines and a [data-table] becomes a working shelf. Click, Enter or Space lifts a book out of its slot; with a mouse or pen you can also drag it up off the shelf. One book is open per shelf; pulling another swaps them. Escape or the spread's "Put it back" button closes it and returns focus to the spine. A link to books.html#shelf-<book> opens that book on arrival.

Turn the table (home)

Each featured book is a [data-slide] (quote, title, price, buttons) and a matching [data-slide-cover], in the same order. data-field, data-field-ink and data-field-soft on the slide set the hero's background, text and secondary text when it is shown; the first slide's values are also written on the hero's style for the first paint. Prev and next buttons, the arrow keys on those buttons, and a sideways swipe on the cover all turn the table.

Shelf filters (books page)

Each button[data-filter] names a shelf (fiction, translated, poetry, non-fiction, childrens, or all). It hides spines whose data-shelf-item and grid groups whose data-grid-group do not match. Add a shelf by adding a chip and using its name on the books.

Cover flip (book page)

[data-flip] holds the front and back cover; the "Turn it over" button turns it, and with a mouse you can drag it round by hand. The back-cover text is repeated in a visually hidden paragraph for screen readers.

Date-due slip (club page)

Past meetings are plain rows with a READ stamp. The button stamps HELD on the row with [data-stamp] and writes a confirmation into [data-stamp-msg]; a second press gives the seat back. It is a front-end gesture only (see Forms).

Opening hours

HOURS at the top of assets/script.js holds each weekday's opening and closing time in decimal hours (9.5 is 9.30), with SHOP_TZ for the shop's time zone. They drive every [data-open-status] line (nav, home hero, visit page, phone menu) and mark today's row in the visit page's hours table. Keep the hours table and the footer in step by hand.

Map and walking routes (visit page)

SHOP_AT, ROUTES and STOPS at the top of the script are [longitude, latitude] coordinates. The two routes were routed on OpenStreetMap foot paths; get your own from https://routing.openstreetmap.de/routed-foot/route/v1/foot/<lng,lat>;<lng,lat>?overview=full&geometries=geojson and paste the coordinates in. Each [data-route-tab] names a route. Without WebGL or the map library, the map area keeps a link to the place on openstreetmap.org.

Forms

The reserve form (book page) and the Ask us form (visit page) are an unwired front end: they check the required fields and show a thank-you line, and nothing leaves the page. To send them, set action and method on each <form> to Formspree, Netlify Forms or your own endpoint, and remove the e.preventDefault() call in initForms().

Phone menu

Below 1100px the nav becomes a Menu button that drops a blue sheet with the five pages set large. It closes with Close, Escape or a tap on the dimmed page, moves focus in when it opens and back to the button when it closes, and marks the current page. Without JavaScript the footer carries the same five links.

Palette

Token Value Use
--blue #1F2C8C Shop colour: nav, footer, club and visit fields, buttons, routes
--white #FFFFFF Page, type on fields
--paper #F6F4EE Tiles, spreads, paper sections
--jacket #FBFAF6 The club slip
--ink #1A1A1F Body copy
--mute #5A5F6B Captions and meta
--blue-soft #B9C1EA Secondary text on blue fields
--blue-mute #4B5394 Secondary text on white

Accessibility and Fallbacks

  • Every spine is a real button with aria-expanded and aria-controls; Escape and "Put it back" return focus to it. Filters and the cover flip use aria-pressed; the route tabs are a tablist with arrow keys.
  • Turning the table announces the new book through a polite live region.
  • Under prefers-reduced-motion, nothing travels and smooth scrolling is off, but every interaction still works as an instant change.
  • Without JavaScript, or if the GSAP CDN is blocked, every book's spread reads in full under its shelf, the first featured book shows, and the footer links reach every page.
  • Text pairs are measured in the stylesheet's first comment; all are 4.5:1 or better.

Dependencies

  • GSAP 3.15.0 with ScrollTrigger (works with 3.12+), from jsDelivr.
  • MapLibre GL 4.7.1 from unpkg on the visit page only, loaded when the map nears the viewport; tiles from OpenFreeMap (no key, OpenStreetMap data).
  • Lenis 1.3.17 for optional smooth scrolling (add ?smooth=off to a URL, or data-smooth="off" on <html>, to turn it off).
  • Fonts (self-hosted, SIL Open Font License): Libre Caslon Display, Libre Caslon Text, League Spartan, Bodoni Moda, Archivo, Caveat.

Images and Credits

Bundled images are WebP derivatives in assets/img/, listed in assets/img-manifest.json. Rebuild them with bun scripts/build-template-assets.ts bookshop-template --force (in the GSAP Vault repo), or replace a file with your own at the same name and size.

  • The shelf (assets/img/shelf/) is cut from one generated photograph, assets/img-src/shelf/shelf-e.jpg, by assets/img-src/shelf/cut-shelf.py.
  • Shop photographs are from Pexels under the Pexels licence (https://www.pexels.com/photo/<id>/; the ids are in the manifest). They are cropped so no real book title reads, with saturation eased slightly. They are stock photographs of other shops, captioned for the example.
  • Fourteen of the cover artworks in assets/img/covers/ were generated (A Year of Soups and The Quiet Carriage have type-only covers) for this template and contain no text; titles, authors and imprints are HTML. Their masters are in assets/img-src/covers/.

Grainger Street Books, its booksellers, books (including Margaret Doyle's A Year of Soups and Tomás Vela's The Quiet Carriage), authors, translators, imprints (Fieldfare, Tidewrack, Cinder Path, Mill Lane Press, Kestle Poetry, Puffling Books), prices, events and phone number are fictional. Grainger Street, Monument Metro and Central Station are real places in Newcastle upon Tyne, and the map shows real streets.

This season's top picks

books.html is a curated selection, not the stock list: its head says the shop holds thousands more and orders anything in print, with a link to the Ask us form on the Visit page. Rename the season in the page head and the nav label (Top picks) to suit.

Worked examples, the events and programmatic API, and the class reference ship with the download, alongside the full source.