A small set of blog layouts, from quick scans to denser indexes. Bring your own stories, covers, and authors.
Post cards
Three straightforward cards with a cover, category, title, and excerpt.
From the blog
Notes on product, design, and shipping interfaces that feel finished.
ProductMar 12, 2026Shipping blocks that match your tokens
How we keep every section restylable without a second design pass.
EngineeringMar 4, 2026A boring install story on purpose
CLI, drop-in, ship — why the path to first paint should feel uneventful.
DesignFeb 21, 2026Light, dark, and everything between
Semantic surfaces so marketing pages don’t need a night-mode rewrite.
"use client";import { cn } from "@/lib/utils";type Blog01Props = { className?: string;};const POSTS = [ { title: "Shipping blocks that match your tokens", excerpt: "How we keep every section restylable without a second design pass.", category: "Product", date: "Mar 12, 2026", image: "/assets/brand/demos/attachments/attachment-1.png", }, { title: "A boring install story on purpose", excerpt: "CLI, drop-in, ship — why the path to first paint should feel uneventful.", category: "Engineering", date: "Mar 4, 2026", image: "/assets/brand/demos/attachments/attachment-2.png", }, { title: "Light, dark, and everything between", excerpt: "Semantic surfaces so marketing pages don’t need a night-mode rewrite.", category: "Design", date: "Feb 21, 2026", image: "/assets/brand/demos/attachments/attachment-3.png", },] as const;export function Blog01({ className }: Blog01Props) { return ( <section className={cn("@container w-full bg-background", className)}> <div className="mx-auto w-full max-w-4xl px-4 py-10 @[32rem]:px-6 @[32rem]:py-14"> <div className="mx-auto max-w-md text-center"> <h2 className="text-xl font-medium tracking-wide text-foreground @[32rem]:text-2xl"> From the blog </h2> <p className="mt-2 text-sm tracking-wide text-muted-foreground"> Notes on product, design, and shipping interfaces that feel finished. </p> </div> <ul className="mt-8 grid grid-cols-1 gap-6 @[40rem]:grid-cols-3 @[40rem]:gap-4"> {POSTS.map((post) => ( <li key={post.title} className="flex min-w-0 flex-col"> <div className="aspect-[16/10] w-full overflow-hidden rounded-xl bg-muted"> <img src={post.image} alt="" className="size-full object-cover" /> </div> <div className="mt-3 flex items-center justify-between gap-3 text-[11px] tracking-wide text-muted-foreground"> <span>{post.category}</span> <span>{post.date}</span> </div> <h3 className="mt-1.5 line-clamp-2 text-sm font-medium tracking-wide text-foreground"> {post.title} </h3> <p className="mt-1.5 line-clamp-2 text-xs tracking-wide text-muted-foreground"> {post.excerpt} </p> </li> ))} </ul> </div> </section> );}Installation
npx @arctis-sh/@arctis-sh/ui@latest add blog-01Usage
import { Blog01 } from "@/components/blocks/blog/blog-01"<Blog01 />Featured + row
One full-width feature followed by three smaller posts in a row.
Latest writing
A featured story up top, then three recent posts underneath.

Product·Mar 18, 2026
Shipping a full marketing kit
Patterns that held up when teams started installing blocks.
DesignMar 10, 2026Token-ready defaults
Restyle every section without a second design pass.
EngineeringMar 2, 2026Keep the CLI boring
Install, import, ship — no ceremony required.
GuidesFeb 24, 2026Compose without fights
Mix heroes, pricing, and FAQs in any order.
"use client";import { cn } from "@/lib/utils";type Blog02Props = { className?: string;};const FEATURED = { title: "Shipping a full marketing kit", excerpt: "Patterns that held up when teams started installing blocks.", category: "Product", date: "Mar 18, 2026", image: "/assets/brand/demos/attachments/attachment-4.png",} as const;const POSTS = [ { title: "Token-ready defaults", excerpt: "Restyle every section without a second design pass.", category: "Design", date: "Mar 10, 2026", image: "/assets/brand/demos/attachments/attachment-1.png", }, { title: "Keep the CLI boring", excerpt: "Install, import, ship — no ceremony required.", category: "Engineering", date: "Mar 2, 2026", image: "/assets/brand/demos/attachments/attachment-2.png", }, { title: "Compose without fights", excerpt: "Mix heroes, pricing, and FAQs in any order.", category: "Guides", date: "Feb 24, 2026", image: "/assets/brand/demos/attachments/attachment-3.png", },] as const;export function Blog02({ className }: Blog02Props) { return ( <section className={cn("@container w-full bg-background", className)}> <div className="mx-auto w-full max-w-4xl px-4 py-10 @[32rem]:px-6 @[32rem]:py-14"> <div className="mx-auto max-w-md text-center"> <h2 className="text-xl font-medium tracking-wide text-foreground @[32rem]:text-2xl"> Latest writing </h2> <p className="mt-2 text-sm tracking-wide text-muted-foreground"> A featured story up top, then three recent posts underneath. </p> </div> <article className="relative mt-8 aspect-[21/9] overflow-hidden rounded-xl bg-muted @[32rem]:aspect-[2.4/1]"> <img src={FEATURED.image} alt="" className="absolute inset-0 size-full object-cover" /> <div className="absolute inset-0 bg-gradient-to-t from-black/70 via-black/20 to-transparent" /> <div className="absolute inset-x-0 bottom-0 p-4 @[32rem]:p-6"> <p className="text-[11px] tracking-wide text-white/75"> {FEATURED.category} <span className="mx-1.5 text-white/40">·</span> {FEATURED.date} </p> <h3 className="mt-1.5 line-clamp-2 text-sm font-medium tracking-wide text-white @[32rem]:text-base"> {FEATURED.title} </h3> <p className="mt-1.5 line-clamp-2 max-w-xl text-xs tracking-wide text-white/75"> {FEATURED.excerpt} </p> </div> </article> <ul className="mt-8 grid grid-cols-1 gap-6 @[40rem]:grid-cols-3 @[40rem]:gap-4"> {POSTS.map((post) => ( <li key={post.title} className="flex min-w-0 flex-col"> <div className="aspect-[16/10] w-full overflow-hidden rounded-xl bg-muted"> <img src={post.image} alt="" className="size-full object-cover" /> </div> <div className="mt-3 flex items-center justify-between gap-3 text-[11px] tracking-wide text-muted-foreground"> <span>{post.category}</span> <span>{post.date}</span> </div> <h3 className="mt-1.5 line-clamp-2 text-sm font-medium tracking-wide text-foreground"> {post.title} </h3> <p className="mt-1.5 line-clamp-2 text-xs tracking-wide text-muted-foreground"> {post.excerpt} </p> </li> ))} </ul> </div> </section> );}Installation
npx @arctis-sh/@arctis-sh/ui@latest add blog-02Usage
import { Blog02 } from "@/components/blocks/blog/blog-02"<Blog02 />Reading list
Compact rows with covers, excerpts, and authors for a denser reading index.
All posts
A simple reading list with author and cover on each row.
ProductMar 12, 2026Shipping blocks that match your tokens
Keep every section restylable without a second design pass.
Maya Chen
EngineeringMar 4, 2026A boring install story on purpose
Why the path to first paint should feel uneventful.
Priya Nair
DesignFeb 21, 2026Light, dark, and everything between
Semantic surfaces so night mode isn’t a rewrite.
Jordan Hale
GuidesFeb 14, 2026Composing pages without layout fights
Mix heroes, pricing, and FAQs without nesting wars.
Chris Ortega
"use client";import { cn } from "@/lib/utils";type Blog03Props = { className?: string;};const POSTS = [ { title: "Shipping blocks that match your tokens", excerpt: "Keep every section restylable without a second design pass.", category: "Product", date: "Mar 12, 2026", author: "Maya Chen", avatar: "/assets/brand/demos/avatars/avatar-1.png", image: "/assets/brand/demos/attachments/attachment-1.png", }, { title: "A boring install story on purpose", excerpt: "Why the path to first paint should feel uneventful.", category: "Engineering", date: "Mar 4, 2026", author: "Priya Nair", avatar: "/assets/brand/demos/avatars/avatar-3.png", image: "/assets/brand/demos/attachments/attachment-2.png", }, { title: "Light, dark, and everything between", excerpt: "Semantic surfaces so night mode isn’t a rewrite.", category: "Design", date: "Feb 21, 2026", author: "Jordan Hale", avatar: "/assets/brand/demos/avatars/avatar-2.png", image: "/assets/brand/demos/attachments/attachment-3.png", }, { title: "Composing pages without layout fights", excerpt: "Mix heroes, pricing, and FAQs without nesting wars.", category: "Guides", date: "Feb 14, 2026", author: "Chris Ortega", avatar: "/assets/brand/demos/avatars/avatar-4.png", image: "/assets/brand/demos/attachments/attachment-5.png", },] as const;export function Blog03({ className }: Blog03Props) { return ( <section className={cn("@container w-full bg-background", className)}> <div className="mx-auto w-full max-w-3xl px-4 py-10 @[32rem]:px-6 @[32rem]:py-14"> <div className="mx-auto max-w-md text-center"> <h2 className="text-xl font-medium tracking-wide text-foreground @[32rem]:text-2xl"> All posts </h2> <p className="mt-2 text-sm tracking-wide text-muted-foreground"> A simple reading list with author and cover on each row. </p> </div> <ul className="mt-8 flex flex-col gap-3"> {POSTS.map((post) => ( <li key={post.title} className="flex gap-4 rounded-xl bg-muted p-3 @[32rem]:p-4" > <div className="hidden size-24 shrink-0 overflow-hidden rounded-lg bg-background @[32rem]:block"> <img src={post.image} alt="" className="size-full object-cover" /> </div> <div className="flex min-w-0 flex-1 flex-col justify-center"> <div className="flex items-center justify-between gap-3 text-[11px] tracking-wide text-muted-foreground"> <span>{post.category}</span> <span>{post.date}</span> </div> <h3 className="mt-1 line-clamp-2 text-sm font-medium tracking-wide text-foreground"> {post.title} </h3> <p className="mt-1 line-clamp-2 text-xs tracking-wide text-muted-foreground"> {post.excerpt} </p> <div className="mt-3 flex items-center gap-2"> <img src={post.avatar} alt="" className="size-5 rounded-full object-cover" /> <span className="text-[11px] tracking-wide text-muted-foreground"> {post.author} </span> </div> </div> </li> ))} </ul> </div> </section> );}Installation
npx @arctis-sh/@arctis-sh/ui@latest add blog-03Usage
import { Blog03 } from "@/components/blocks/blog/blog-03"<Blog03 />