Blocks vs Components: What Survives a Rebrand
The core architectural split in ShipAny TanStack — disposable blocks read i18n and wire content, durable components render anything you feed them.
Every template promises "easy customization," then makes you grep through twelve files to change a headline. ShipAny TanStack avoids that with one rule:
Demo content belongs in blocks. Reusable UI belongs in components. Auth, checkout, and support behavior belongs in features.
Blocks are disposable
Blocks live in src/blocks/ and are product sections. Page routes read their structured JSON with useMessages() and pass copy to presentation blocks such as Hero. Shared capabilities such as Pricing and Footer read their own prepared resource. Route and layout dependencies are loaded before rendering. They're the demo material: when you start a real project, you delete them and write your own.
import { useMessages } from '@/core/i18n/messages';
import { FAQ } from '@/blocks/faq';
export function HomeFAQ() {
const text = useMessages('pages/home');
return <FAQ content={text.faq} />;
}
Each presentation section exports its content type from its own component file (for example, FAQContent in src/blocks/faq.tsx). Choose the section, read that type, then write the matching nested object in the page JSON. Action slots and runtime data remain separate props.
Components are durable
Components live in src/components/. Product copy arrives via props; shared controls read their own shared/* resource with the same useMessages() entry point. SiteHeader owns shared navigation copy; generic PricingTable and AppSidebar render data and content supplied by callers. That's exactly why they survive every rebrand.
Why the split matters
When you rebrand or start a new project from the template:
- Keep
src/components/*andsrc/features/*— reusable UI and client workflows. - Rewrite
src/blocks/*— the content wiring. - Rewrite the translation JSON files that feed the blocks.
The page files themselves stay tiny — src/routes/(pages)/index.tsx is page composition, a stack of blocks. Changing your entire landing page touches blocks and JSON, never the primitives. The split is not cosmetic; it's what makes customization a rewrite of intent instead of a fight with someone else's design decisions.