Blocks

Several components already wired together — a login popup, a mini dashboard, a swap card, a widget — copied as one working screen.

Using the catalog 3 min read

TL;DR · the pieces, already cooked together

  • A block is several catalog components assembled into one working screen.
  • The copy is the assembly plus every component inside it. Nothing left to hunt down.
  • Blocks emit events; you wire them to your own backend in one listener.

A block is the rung between one component and a whole page section:

  1. Component · a button
  2. Block · a login popup
  3. Section · a landing-page band

A login popup, a mini dashboard, a swap card, a settings panel, a widget — several catalog components already assembled and wired to real state.

Browse them at Blocks. The chips filter by what the piece is: Auth, Dashboard, Cards, Widgets, Commerce, Crypto, Chat, Forms, Media, Settings, Onboarding.

What you actually get

The point of a block is the part a component library never hands you: the composition. Which pieces, in what order, at what spacing, sharing which bit of state. BlkLoginPopup invents nothing — the fields are VsInput, the actions are VsButton, the rule is VsSeparator, the toggle is VsCheckbox — and what it adds is the working screen those four make together.

So the copy you get is the assembly plus every component it uses:

BlkLoginPopup.vuethe assembly
components/VsInput.vueused inside
components/VsButton.vueused inside
components/VsSeparator.vueused inside
components/VsCheckbox.vueused inside

One paste-ready bundle. Nothing is left as an import you have to go and find.

Blocks are Vue SFCs

Components, sections and animations ship as native custom elements — one self-contained vs-*.js, zero dependencies. Blocks are Vue single-file components instead, and deliberately so: a block’s whole value is that it imports the catalog’s own pieces, and a “zero-dependency single file” would have to inline them and stop being an assembly at all.

<script setup lang="ts">
import VsInput from './components/VsInput.vue';
import VsButton from './components/VsButton.vue';
</script>

If you are not on Vue, the block is still the best reference you can get for the layout and the wiring — and every component it uses has a framework-neutral vs-*.js port of its own in Components.

Every prop is a control

Same rule as the rest of the catalog: nothing is hardcoded. Titles, labels, which optional rows appear — all props with defaults, all editable from the control bar before you copy, all visible in the preview as you change them.

The block, handing submit to your code.

Blocks emit events rather than doing the work: BlkLoginPopup emits submit with the form payload and social with the provider. Wiring it to your own auth endpoint is one listener.

Responsive by container query

A block is judged inside a box — a catalog card, a phone frame, a column of your app — not at the width of the window. Its breakpoints are therefore @container queries, so it lays itself out from the space it is actually given.

Drop one into a 380px column and it behaves like it is on a phone, whatever the browser window is doing.

Adding one

pnpm new:block --name SwapCard --category Finance --group crypto
Missing piece? Go build the real component first.

That scaffolds src/blocks/BlkSwapCard/ with its meta.ts and a Vue file already set up with the container query and the “import, do not invent” rule in a comment at the top.

If a piece the block needs does not exist yet, build it as a real component first and import it — a one-off widget buried inside a block is a component nobody else can find.