Building blocks for responsive designBuild pages from blocks, not from scratch Content Blocks are responsive, accessible web components for the sections every page is made of. Use them as the building blocks of your designs, and as the content model of your headless CMS, in any framework or none. Get startedSee the components
A video hero that plays a film inside itself
<content-hero-block id="hero">
  <content-image slot="background"
    src="loop-phone.mp4|loop-desktop.mp4">
  </content-image>
  <content-text-block slot="content">
    <content-line tag="h1">Melt in moisture</content-line>
    <content-button href="#film">Play film</content-button>
  </content-text-block>
</content-hero-block>

<content-overlay id="film" label="The film"
  target="#hero" position="fixed|absolute">
  <content-video slot="content" autoplay="true"
    fit-container="true"
    src="https://youtube.com/watch?v=aqz-KE-bpKQ">
  </content-video>
</content-overlay>
The problemContent pages keep getting rebuilt, one at a time Marketing and editorial pages are made of the same few sections. Teams still build them again for every page, every framework and every redesign. 01Every page is rebuilt from scratchEach landing page restyles the same hero, grid and carousel with one-off CSS and a fresh set of media queries.02Components are locked to one frameworkA hero written in React cannot be reused by the CMS template, the static microsite or the team on Vue.03Quality drifts with every copyCarousels without pause buttons, dialogs that lose focus, images that load too early. Each copy fixes them, or forgets to.
What it solvesOne set of blocks for every page you buildResponsive by attributeGive a prop one value per breakpoint, like columns="1|2|4". No media queries to write.Works with any stackStandard web components. Use them in plain HTML, React, Vue, Astro or any CMS template.Your CSS just worksComponents render in the light DOM, with no shadow boundary between them and your stylesheet.Accessible by defaultKeyboard support, focus-trapped dialogs, labelled carousels with a pause button, and axe tests on every component.Loads only what is usedEach component’s code downloads when its tag first appears, or import one component at a time.Ready for a headless CMSEvery option is plain text, so a layout can be stored as content and changed without a deploy.
Built for headless CMSYour content model, already built Content Blocks give a headless CMS a ready-made set of sections. Editors compose pages from them, and developers render them without writing a component for each one. Layouts are contentEvery option is a short text value, so a whole section lives in your CMS as a few fields, and editors change it without a deploy.Responsive in one fieldA value like 1|2|4 holds the setting for every screen size, so one field controls the phone and desktop layouts.Fields from the docsdocs.json describes every option with its type, choices and default, so your CMS fields can be generated instead of written by hand.Renders in any front endAn entry becomes plain HTML tags, so Astro, Next.js or a server template renders it the same way.
Stored in your CMS
{
  "block": "content-split-block",
  "columns": "1|2",
  "reverse": "false|true",
  "image": "phone.jpg|desktop.jpg",
  "heading": "Melt in moisture"
}
Rendered on your site
<content-split-block columns="1|2" reverse="false|true">
  <content-image slot="column1" src="phone.jpg|desktop.jpg">
  </content-image>
  <content-line slot="column2" tag="h2">
    Melt in moisture
  </content-line>
</content-split-block>
How it worksOne value per breakpoint Responsive options take a value for each screen size, smallest first, separated by pipes. This grid is one column on phones, two from 768px and three from 1024px. Resize the window to watch it change.
<content-grid-formatter type="grid"
  columns="1|2|3" column-gap="1.5rem">
  <article>…</article>
  <article>…</article>
  <article>…</article>
</content-grid-formatter>
Live result
DemosWhole pages, built only from blocks Every section of these made-up sites is a Content Block. Only each brand's stylesheet changes. Makeup shopHero carousel, product touts with quick shop, split blocks and FAQs.Hair care shopVideo hero, product carousels in tabs, text over photo cards and reviews.Skincare campaignA launch page with a film in the hero, a slideshow and step by step instructions.To-do app homepageAn app window with floating cards, a feature grid, pricing in tabs and a video tour.
The componentsFifteen blocks that cover most pagesBlocksPage sections
  • <content-hero-block>
  • <content-split-block>
  • <content-text-block>
  • <content-tout-block>
ElementsContent inside them
  • <content-button>
  • <content-image>
  • <content-line>
  • <content-video>
FormattersLayout and spacing
  • <content-grid-formatter>
  • <content-spacer>
ComponentsInteractive patterns
  • <content-accordion>
  • <content-carousel>
  • <content-navigation-block>
  • <content-overlay>
  • <content-tabs>
Get startedAdd it in a minuteFrom a CDNOne script tag. Each component loads the first time its tag appears.
<script type="module"
  src="https://cdn.jsdelivr.net/npm/@content-blocks/js/dist/content-blocks/content-blocks.esm.js">
</script>
From npmImport the loader, or one component at a time for your bundler.
$ npm install @content-blocks/js
QuestionsDo I need a framework?No. Content Blocks are standard custom elements, so a single script tag is enough. They also work inside React, Vue, Astro and other frameworks.Can I use my own design?Yes. The components handle layout, spacing and behaviour, and render without a shadow DOM, so your own stylesheet sets the look.How do breakpoints work?Responsive props take one value per breakpoint, smallest first, separated by pipes. 1|2|4 means one on phones, two from 768px and four from 1024px. You can set your own breakpoints.Which CMS does it work with?Any headless CMS that can store text fields. A block is a tag and a few text values, so it fits whatever content model you already have, and your front end renders it as HTML.What does it cost?Nothing. Content Blocks is open source under the MIT license.
Start with one blockDrop a single component into a page you already have, and grow from there.Get startedView on GitHub