Safely extract and modularize tabs, sub-views, and large components from monolithic React files with zero regressions.
Install
npx skillscat add shadowsys-memphis/brainguardian/modularize-react-tabs Install via the SkillsCat registry.
Modularize React Tabs Skill
This skill provides a battle-tested protocol for decomposing monolithic React view files (e.g. admin-view.tsx) into clean, single-responsibility tab components.
The Golden Rules of Modularization
- One Component per Pass: Never extract multiple tabs or sections at once. Always isolate, move, wire, verify, and commit one component at a time.
- Pure Relocation (Zero Drive-By Refactoring): When moving code, do NOT try to "improve" logic, rename props, or modernize syntax. Move the exact implementation as-is. Refactoring logic comes after modularization, never during.
- Pre-Flight and Post-Flight Typecheck: Always run
pnpm run typecheckbefore cutting code and immediately after wiring the new component. If typecheck fails, fix the imports before touching anything else.
The 6-Step Extraction Workflow
Step 1: Pre-Flight Check
Ensure the codebase builds cleanly before starting:
pnpm run typecheckIf errors exist, fix or note them first. Do not refactor on top of a broken build.
Step 2: Identify Component Boundaries & Dependencies
Inspect the tab/section in the monolith:
- Props & Callbacks: What does the component receive from the parent? (e.g.
onNavigate,activeTab,isLocal) - Local Types & Constants: Are there category labels, icons, or interface definitions used only by this tab?
- Shared State / Context: Does it consume hooks (
useVault(),useQueryClient(), etc.) directly? (Tabs using React Query hooks are self-contained and easiest to move!)
Step 3: Create the Destination File
Create the new file under a dedicated directory, e.g.:artifacts/brain-app/src/pages/admin/tabs/<tab-name>-tab.tsx
Structure template:
import React, { useState } from "react";
// 1. UI components (from @/components/ui/...)
// 2. Icons (from lucide-react)
// 3. API hooks / types (from @workspace/api-client-react)
// 4. Context / Utils (from @/lib/...)
interface <TabName>TabProps {
onNavigate?: (tab: string) => void;
}
export function <TabName>Tab({ onNavigate }: <TabName>TabProps) {
// Extracted implementation moved here intact
}Step 4: Wire Component into the Parent Monolith
In the parent file (e.g. admin-view.tsx):
- Import the newly created tab:
import { <TabName>Tab } from "./admin/tabs/<tab-name>-tab"; - Replace the inline
<TabName>Tabfunction definition and any exclusively local sub-components/constants with the imported component. - Keep the render switch clean:
{activeTab === "<tab-name>" && <<TabName>Tab onNavigate={setActiveTab} />}
Step 5: Post-Flight Verification
Run the typecheck to confirm all imported symbols, hooks, and types match:
pnpm run typecheckStep 6: Prune Dead Parent Imports
Check if the parent monolith now has unused imports (e.g., specific Lucide icons or API hooks that were only used by that extracted tab) and clean them up.