✅ Best Practices & Principles — Mosaik
Mosaik is a modern, headless-first UI framework for building robust Next.js 15 + React apps — guiding you to create reusable, maintainable, and lightning-fast UIs with minimal bloat.
By simply following these few principles and architectural choices, you’ll massively boost the scalability, flexibility, composability, simplicity, and code quality of your headless React codebase — without adding unnecessary complexity.
🔑 Mosaik TL;DR
- Action/Effect state: pure logic, serializable actions, side effects only in useEffect.
- Context-aware, intent-driven components — expose actions, not brittle props.
- Themeable, tree-shakable components — one file per variant, dynamically imported.
- Slot-based layout system for flexible, CMS-friendly UIs.
- Built-in first: Next.js, React, Tailwind — SSR/ISR/SSG out of the box.
- Prerender static content wherever possible.
📌 Principles & Intentions
1️⃣ Action/Effect Based State Management
Mosaik’s state management follows a clear Action/Effect mindset:
- Actions describe what should happen — e.g.,
COLLAPSE
,MINIMIZE
,CLOSE
. - Effects handle how that action runs — like fetching data, mutations, or side effects.
- Actions & Effects should always be serializable — so you can log, replay, or test them easily.
- Action generators are fine: e.g.
dispatch(minimize({ id }))
— the intent stays clear.
- Action generators are fine: e.g.
- Keep all functions and logic pure by default.
- Never include side effects inside normal functions — keep them pure and testable.
- The only place side effects should run is inside dedicated effect runners (typically invoked in
useEffect
). - State management should handle this orchestration for you.
2️⃣ Context-Aware, Intent-Driven Components
Mosaik components are designed by intention, not just by function.
- Use contexts to expose actions — not tight, one-off APIs.
- E.g., a
Sidebar
provides aCOLLAPSE
action to its children. - A
Window
component exposesMINIMIZE
,CLOSE
,MAXIMIZE
,DOCK
. - A
DesktopContent
might exposeFULLSCREEN
.
- E.g., a
- Reusable components like an
ActionBar
can render any available actions without knowing how they work. - Intent over implementation — build generic UI building blocks that can be themed, swapped, or extended.
- Keep it simple: Build like you’re building a UI framework — not a single-purpose UI.
Mindset: Write your components and logic so they could live in a library like Material UI. Avoid one-off props or bespoke components for every tiny variation.
3️⃣ Themeable Components
Every component is one file per theme variant, stored under:
themes/
- Components are dynamically imported.
- Only the active theme’s code is bundled — tree-shakable by default.
- Keep styling flexible with Tailwind classes.
4️⃣ Slot-Based System for Layout Flexibility
Mosaik relies on a slot-based architecture:
- Every piece of UI exposes slots for injecting custom content.
- Enables rich CMS-driven layouts.
- Makes theme overrides trivial.
- Encourages reuse instead of copy-pasting variations.
5️⃣ Tailwind CSS
- Tailwind is the default styling engine.
- Rapid prototyping without custom CSS.
- Utility classes make theming clean and easy to reason about.
6️⃣ TypeScript Everywhere
- Type your
Props
andActions
. - Validate your routes, contexts, and API shapes.
- Reduce runtime bugs with static guarantees.
🛠️ Built-In First
Mosaik sticks as close as possible to Next.js, React, and Tailwind:
- Use Next.js App Router for routing and layouts.
- Leverage
generateStaticParams
for SSG. - Use
revalidate
for ISR. - Use SSR where dynamic data is essential.
- Keep CSR components tightly scoped to where you truly need local interactivity.
- Render on the server by default. Hydrate only where needed.
⚡ Performance-First by Design
Performance is not an afterthought — it’s the baseline:
- Prebuild static pages wherever possible.
- Keep your content up-to-date with ISR.
- Server-render where data must be fresh.
- Client-render only what needs state.
- Theme imports are tree-shakable — no unused design code in your bundle.
💡 Takeaway
Mosaik’s philosophy: Build like you’re building a reusable UI library — not a one-off app.
- Keep logic pure and side-effect free by default.
- Run side effects only in dedicated runners managed by your state hooks.
- Design for intent, not just functionality.
- Expose actions, not brittle props.
- Compose UIs with slots.
- Keep styling consistent with Tailwind.
- Rely on Next.js and React for what they do best.
Stay flexible, stay maintainable — one elegant block at a time.
Happy building!