Astro blocks beat a component library
A component library gives you a dependency. A block gives you a file. The difference shows up the first time you need something the library did not anticipate.
Most UI kits ship as a package. You install it, import a Hero, pass props, and accept whatever the author decided a Hero should be. The moment your design calls for something slightly different, you are reading node_modules and writing overrides.
A block inverts that. It is a single .astro file you copy into your own components folder. From then on it is your code — you edit it directly, in place, with no wrapper and nothing to override.
What makes a section a block
Three properties, and all three matter:
It is self-contained. No imports from a shared internal module, no helper file that has to come along. Copy the file and it renders.
Its content arrives through props. Nothing is hardcoded into the markup, so the same block serves an architecture studio and a SaaS pricing page without being forked.
Its styles are scoped. Dropping it into an existing project cannot break the styles already there, and the project cannot break the block.
If copying one file into an empty project does not render, it was a component, not a block.
Why the copy-paste model wins here
The usual objection is duplication: copies drift, and a fix in one place does not reach the others. That is a real cost in application code, where the same logic runs in twenty screens.
Page sections are not that. A hero on the homepage and a hero on the pricing page are meant to diverge — different copy, different emphasis, often a different layout by month three. Forcing them to share an abstraction produces a component with nine boolean props and a rendering branch for each, which nobody can safely change.
Copies drift, and for marketing sections drifting is the requirement rather than the bug.
Consistency without coupling
The obvious risk is a site that looks assembled from parts. The fix is not shared components — it is shared tokens. Put colour, spacing, radii and the type scale in one layout file as CSS custom properties, and have every block read from them.
:root {
--text: #21201c;
--line: rgba(24, 24, 27, 0.1);
--radius-card: 16px;
--maxw: 1440px;
}Change --maxw once and every section follows. The blocks stay independent files; only the vocabulary is shared. That is the same separation a design system makes between components and foundations, applied where it actually pays.
Where blocks are the wrong tool
They are a poor fit for anything with real logic. A data table with sorting, a multi-step form with validation, an authenticated dashboard widget — those want a genuine component with tests, versioned in one place.
Blocks earn their keep on the layer above: the sections a marketing site is made of, where the work is layout and copy rather than behaviour, and where being able to change one page without touching another is worth more than reuse.