diff --git a/CHANGELOG.md b/CHANGELOG.md
index 07a6991..1e08310 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,20 +1,11 @@
-## 1.3.0 (2026-03-28)
+## 1.4.0 (2026-05-27)
### Feat
-- fixing low effor issues, improveing e2e tests
-
-## 1.2.2 (2026-03-03)
-
-### Fix
-
-- fixing theme switcher for default light mode
-
-## 1.2.1 (2026-01-16)
+- adding outline functionality
### Fix
-- updating packages
- lint/formatting, pre-commits revamp
## 1.1.2 (2025-10-24)
diff --git a/package.json b/package.json
index 697ae66..e83be35 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "checkquest",
"private": true,
- "version": "1.3.0",
+ "version": "1.4.0",
"type": "module",
"packageManager": "pnpm@10.28.0",
"engines": {
diff --git a/public/templates/react.json b/public/templates/react.json
index f3d3990..ce41df2 100644
--- a/public/templates/react.json
+++ b/public/templates/react.json
@@ -6,7 +6,7 @@
"name": "React",
"description": "React developer checklist",
"createdAt": "2025-09-21T13:02:32.480Z",
- "updatedAt": "2025-09-21T13:02:32.480Z",
+ "updatedAt": "2026-05-27T00:00:00.000Z",
"sections": [
{
"id": "general",
@@ -30,6 +30,36 @@
"text": "Keys in lists",
"score": 1,
"extra": false
+ },
+ {
+ "id": "syntheticEvents",
+ "text": "Synthetic Events",
+ "score": 1,
+ "extra": false
+ },
+ {
+ "id": "fragments",
+ "text": "Fragments",
+ "score": 1,
+ "extra": false
+ },
+ {
+ "id": "controlledVsUncontrolled",
+ "text": "Controlled vs Uncontrolled Components",
+ "score": 2,
+ "extra": false
+ },
+ {
+ "id": "lifecycle",
+ "text": "Component Lifecycle",
+ "score": 2,
+ "extra": false
+ },
+ {
+ "id": "reconciliation",
+ "text": "Reconciliation & Fiber Architecture",
+ "score": 3,
+ "extra": true
}
]
},
@@ -77,7 +107,25 @@
"score": 3,
"extra": true
},
- { "id": "useId", "text": "useId", "score": 1, "extra": true }
+ { "id": "useId", "text": "useId", "score": 1, "extra": true },
+ {
+ "id": "customHooks",
+ "text": "Custom Hooks",
+ "score": 2,
+ "extra": false
+ },
+ {
+ "id": "useDeferredValue",
+ "text": "useDeferredValue",
+ "score": 3,
+ "extra": true
+ },
+ {
+ "id": "useImperativeHandle",
+ "text": "useImperativeHandle",
+ "score": 2,
+ "extra": true
+ }
]
},
{
@@ -123,6 +171,36 @@
"text": "Error Boundaries",
"score": 2,
"extra": false
+ },
+ {
+ "id": "routing",
+ "text": "Routing in React",
+ "score": 2,
+ "extra": false
+ },
+ {
+ "id": "reactCompiler",
+ "text": "React Compiler",
+ "score": 3,
+ "extra": true
+ },
+ {
+ "id": "forwardRef",
+ "text": "forwardRef",
+ "score": 2,
+ "extra": false
+ },
+ {
+ "id": "suspense",
+ "text": "Suspense & React.lazy",
+ "score": 2,
+ "extra": false
+ },
+ {
+ "id": "compoundComponents",
+ "text": "Compound Components",
+ "score": 3,
+ "extra": true
}
]
},
@@ -167,6 +245,12 @@
"text": "Sass/Less",
"score": 1,
"extra": true
+ },
+ {
+ "id": "cssReset",
+ "text": "CSS Reset",
+ "score": 1,
+ "extra": false
}
]
},
@@ -223,9 +307,9 @@
"extra": true
},
{
- "id": "react",
- "text": "Reset Styles",
- "score": 1,
+ "id": "reactProfiler",
+ "text": "React Profiler",
+ "score": 2,
"extra": true
}
]
@@ -271,6 +355,12 @@
"score": 3,
"extra": true
},
+ {
+ "id": "reactDevTools",
+ "text": "React DevTools",
+ "score": 1,
+ "extra": true
+ },
{ "id": "ai", "text": "AI", "score": 2, "extra": true },
{
"id": "cicd",
@@ -297,6 +387,13 @@
"score": 2,
"extra": true
},
+ { "id": "isr", "text": "ISR (Next.js)", "score": 1, "extra": true },
+ {
+ "id": "nextJsRouting",
+ "text": "Routing in Next.js (app, pages)",
+ "score": 2,
+ "extra": true
+ },
{
"id": "otherFrameworks",
"text": "Other frameworks (Astro, Tanstack, Gatsby)",
diff --git a/public/templates/react_outline.json b/public/templates/react_outline.json
new file mode 100644
index 0000000..2bf176c
--- /dev/null
+++ b/public/templates/react_outline.json
@@ -0,0 +1,1588 @@
+{
+ "id": "react_outline",
+ "checklistId": "react",
+ "version": "1.0.0",
+ "name": "React Developer Training Outline",
+ "description": "Study guide and key concepts for each topic in the React developer checklist",
+ "createdAt": "2026-05-27T00:00:00.000Z",
+ "updatedAt": "2026-05-27T00:00:00.000Z",
+ "sections": [
+ {
+ "id": "general",
+ "title": "General",
+ "topics": [
+ {
+ "id": "jsx",
+ "title": "JSX",
+ "summary": "JSX is a syntax extension for JavaScript that lets you write HTML-like markup inside JS files. Babel/SWC compiles it to `React.createElement()` calls at build time.",
+ "keyPoints": [
+ "Compiles to React.createElement(type, props, ...children)",
+ "Must have a single root element — use Fragments to avoid extra DOM nodes",
+ "HTML attributes are camelCase: className, htmlFor, onClick",
+ "JavaScript expressions go inside {curly braces}",
+ "Self-closing tags must be closed: , ",
+ "Conditional rendering: ternary ({cond ? : }) or short-circuit ({cond && })",
+ "JSX is not HTML — style takes an object, not a string"
+ ],
+ "resources": [
+ {
+ "title": "Writing Markup with JSX",
+ "url": "https://react.dev/learn/writing-markup-with-jsx"
+ },
+ {
+ "title": "JavaScript in JSX with Curly Braces",
+ "url": "https://react.dev/learn/javascript-in-jsx-with-curly-braces"
+ }
+ ]
+ },
+ {
+ "id": "virtualDom",
+ "title": "Virtual DOM",
+ "summary": "The Virtual DOM is an in-memory JavaScript representation of the real DOM. React uses it to batch and minimize actual DOM updates by diffing the previous and next virtual trees.",
+ "keyPoints": [
+ "React keeps a virtual tree in memory mirroring the real DOM",
+ "On state/prop change, a new virtual tree is created and compared (diffing)",
+ "Only changed nodes are applied to the real DOM (patching/reconciliation)",
+ "Diffing runs in O(n) using heuristics: same element type = update, different type = replace whole subtree",
+ "Keys help React match list items across renders",
+ "React Fiber is the internal engine that makes reconciliation interruptible"
+ ],
+ "resources": [
+ {
+ "title": "Preserving and Resetting State",
+ "url": "https://react.dev/learn/preserving-and-resetting-state"
+ },
+ {
+ "title": "React Fiber Architecture (community)",
+ "url": "https://github.com/acdlite/react-fiber-architecture"
+ }
+ ]
+ },
+ {
+ "id": "oneWayDataFlow",
+ "title": "One-way data flow",
+ "summary": "Data in React flows in a single direction — from parent to child via props. Children communicate upward by calling callback functions passed as props.",
+ "keyPoints": [
+ "Props flow down: parent → child",
+ "Events flow up: child calls a function prop to notify parent",
+ "Makes data flow predictable and easy to trace and debug",
+ "Contrast with two-way binding (Angular ngModel, Vue v-model)",
+ "Lifting state up: move shared state to the closest common ancestor",
+ "Prop drilling: passing props through many layers — solved by Context or a state manager"
+ ],
+ "resources": [
+ {
+ "title": "Sharing State Between Components",
+ "url": "https://react.dev/learn/sharing-state-between-components"
+ },
+ {
+ "title": "Thinking in React",
+ "url": "https://react.dev/learn/thinking-in-react"
+ }
+ ]
+ },
+ {
+ "id": "keysInLists",
+ "title": "Keys in lists",
+ "summary": "Keys are stable string/number identifiers that help React match rendered list items to their previous versions across re-renders, enabling efficient updates.",
+ "keyPoints": [
+ "Keys must be unique among siblings (not globally unique)",
+ "Use stable IDs from your data source — not array index if the list can reorder",
+ "Using index as key causes bugs with stateful items, animations, and focus",
+ "Keys are not passed as props — use a separate prop if the child needs the ID",
+ "Missing keys = React warns and falls back to less efficient reconciliation",
+ "Keys should be on the outermost element returned in a .map() call"
+ ],
+ "resources": [
+ {
+ "title": "Rendering Lists",
+ "url": "https://react.dev/learn/rendering-lists"
+ }
+ ]
+ },
+ {
+ "id": "syntheticEvents",
+ "title": "Synthetic Events",
+ "summary": "React wraps native browser events in a SyntheticEvent object that normalizes behavior across browsers. Since React 17, events are attached to the root container rather than document.",
+ "keyPoints": [
+ "SyntheticEvent wraps the native event with a consistent cross-browser API",
+ "React uses event delegation — one listener at the root, not per element",
+ "Access the native event via e.nativeEvent",
+ "Pre-React 17: event pooling (events reused — had to call e.persist()); removed in v17+",
+ "Stopping propagation: e.stopPropagation(), e.preventDefault()",
+ "All standard DOM events are supported with the on prefix: onClick, onChange, onKeyDown, onSubmit"
+ ],
+ "resources": [
+ {
+ "title": "Responding to Events",
+ "url": "https://react.dev/learn/responding-to-events"
+ },
+ {
+ "title": "React Event Object Reference",
+ "url": "https://react.dev/reference/react-dom/components/common#react-event-object"
+ }
+ ]
+ },
+ {
+ "id": "fragments",
+ "title": "Fragments",
+ "summary": "Fragments let you group multiple children elements without adding extra nodes to the DOM — useful when a component must return multiple siblings.",
+ "keyPoints": [
+ "Shorthand: <>> — cannot accept props",
+ "Full form: — supports the key prop when mapping",
+ "Prevents unnecessary wrapper
nodes that break CSS (flex/grid children, table rows)",
+ "Particularly important for
/
and
/
/
structures",
+ "Zero cost — fragments produce no DOM output"
+ ],
+ "resources": [
+ {
+ "title": "Fragment Reference",
+ "url": "https://react.dev/reference/react/Fragment"
+ }
+ ]
+ },
+ {
+ "id": "controlledVsUncontrolled",
+ "title": "Controlled vs Uncontrolled Components",
+ "summary": "Controlled components have their form value driven by React state. Uncontrolled components let the DOM hold the value, accessed imperatively via refs.",
+ "keyPoints": [
+ "Controlled: value prop + onChange handler — React is the single source of truth",
+ "Uncontrolled: defaultValue (not value) + useRef to read imperatively",
+ "Controlled gives real-time access: instant validation, conditional rendering, formatting",
+ "Uncontrolled is simpler for file inputs ( is always uncontrolled)",
+ "React Hook Form uses uncontrolled inputs for performance (fewer re-renders)",
+ "Never switch between controlled/uncontrolled for the same input — causes warnings"
+ ],
+ "resources": [
+ {
+ "title": "Controlled and Uncontrolled Inputs",
+ "url": "https://react.dev/reference/react-dom/components/input#controlling-an-input-with-a-state-variable"
+ },
+ {
+ "title": "React Hook Form",
+ "url": "https://react-hook-form.com/"
+ }
+ ]
+ },
+ {
+ "id": "lifecycle",
+ "title": "Component Lifecycle",
+ "summary": "React components go through mount, update, and unmount phases. Function components use useEffect to handle all lifecycle phases; class components have explicit lifecycle methods.",
+ "keyPoints": [
+ "Mount: component renders and is inserted into the DOM",
+ "Update: re-renders when state or props change",
+ "Unmount: component is removed from the DOM — run cleanup",
+ "useEffect(() => { setup; return cleanup; }, [deps]) covers all three phases",
+ "No deps array = runs after every render",
+ "[] = runs once after mount, cleanup on unmount",
+ "[dep] = runs when dep changes; cleanup before next run",
+ "Class equivalents: componentDidMount, componentDidUpdate, componentWillUnmount",
+ "getDerivedStateFromProps and getSnapshotBeforeUpdate for advanced cases"
+ ],
+ "resources": [
+ {
+ "title": "Lifecycle of Reactive Effects",
+ "url": "https://react.dev/learn/lifecycle-of-reactive-effects"
+ },
+ {
+ "title": "Synchronizing with Effects",
+ "url": "https://react.dev/learn/synchronizing-with-effects"
+ }
+ ]
+ },
+ {
+ "id": "reconciliation",
+ "title": "Reconciliation & Fiber Architecture",
+ "summary": "Reconciliation is React's diffing algorithm that computes the minimal set of DOM changes. Fiber is React's internal reimplementation of the reconciler enabling incremental, interruptible rendering.",
+ "keyPoints": [
+ "React diffs element type first: different type = full subtree replacement",
+ "Same type = update props in place, recurse into children",
+ "List diffing uses keys to map old children to new children in O(n)",
+ "Fiber: each component instance is a 'fiber' — a unit of work with priority",
+ "Fiber tree: work-in-progress tree built alongside the current tree (double buffering)",
+ "Concurrent Mode: Fiber allows React to pause/resume/abort renders",
+ "Priority lanes: user input (high) preempts background data updates (low)",
+ "Commit phase: once a complete work-in-progress tree is ready, React flushes changes synchronously to the DOM"
+ ],
+ "resources": [
+ {
+ "title": "What is Concurrent React?",
+ "url": "https://react.dev/blog/2022/03/29/react-v18#what-is-concurrent-react"
+ },
+ {
+ "title": "React Fiber Architecture (community deep-dive)",
+ "url": "https://github.com/acdlite/react-fiber-architecture"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "hooks",
+ "title": "Hooks",
+ "topics": [
+ {
+ "id": "useState",
+ "title": "useState",
+ "summary": "useState adds local, reactive state to function components. It returns a current value and a setter; calling the setter schedules a re-render with the new value.",
+ "keyPoints": [
+ "const [state, setState] = useState(initialValue)",
+ "Initial value can be a lazy initializer function: useState(() => expensiveCompute())",
+ "Setter can take a value or an updater function: setState(prev => prev + 1)",
+ "Always use the functional form when new state depends on old state",
+ "State updates are asynchronous — the new value is available on the next render",
+ "React 18: automatic batching groups multiple setState calls in async code too",
+ "Each useState call is independent; split state by concern, not into one big object"
+ ],
+ "resources": [
+ {
+ "title": "useState Reference",
+ "url": "https://react.dev/reference/react/useState"
+ },
+ {
+ "title": "State: A Component's Memory",
+ "url": "https://react.dev/learn/state-a-components-memory"
+ }
+ ]
+ },
+ {
+ "id": "useReducer",
+ "title": "useReducer",
+ "summary": "useReducer manages complex state with a pure reducer function and dispatched actions — an alternative to useState when state transitions involve multiple sub-values or complex logic.",
+ "keyPoints": [
+ "const [state, dispatch] = useReducer(reducer, initialState)",
+ "Reducer signature: (state, action) => newState — must be pure",
+ "Actions typically follow { type, payload } convention (like Redux)",
+ "Prefer over useState when: next state depends on multiple fields, or logic is complex/shared",
+ "dispatch has a stable reference — safe to pass down without useCallback",
+ "Can pass dispatch instead of multiple setter callbacks to child components",
+ "Initialize lazily: useReducer(reducer, arg, initFn) — initFn(arg) called once"
+ ],
+ "resources": [
+ {
+ "title": "useReducer Reference",
+ "url": "https://react.dev/reference/react/useReducer"
+ },
+ {
+ "title": "Extracting State Logic into a Reducer",
+ "url": "https://react.dev/learn/extracting-state-logic-into-a-reducer"
+ }
+ ]
+ },
+ {
+ "id": "useEffect",
+ "title": "useEffect",
+ "summary": "useEffect synchronizes a component with an external system — API calls, subscriptions, DOM manipulation — running after render and optionally cleaning up before the next run or unmount.",
+ "keyPoints": [
+ "Runs after the browser has painted — not synchronous with render",
+ "Dependency array controls when it re-runs: [] = once, [dep] = on dep change, omitted = every render",
+ "Return a cleanup function to cancel subscriptions, timers, abort controllers",
+ "In React 18 StrictMode (dev only): effects run twice to catch missing cleanups",
+ "Do NOT use to sync two pieces of React state — use derived state or useMemo instead",
+ "Common pitfalls: missing dependencies (stale closure), infinite loops (setting state without guard), forgetting cleanup"
+ ],
+ "resources": [
+ {
+ "title": "useEffect Reference",
+ "url": "https://react.dev/reference/react/useEffect"
+ },
+ {
+ "title": "You Might Not Need an Effect",
+ "url": "https://react.dev/learn/you-might-not-need-an-effect"
+ }
+ ]
+ },
+ {
+ "id": "useLayoutEffect",
+ "title": "useLayoutEffect",
+ "summary": "useLayoutEffect fires synchronously after all DOM mutations but before the browser paints — use it to read layout metrics or imperatively fix the DOM before the user sees it.",
+ "keyPoints": [
+ "Identical signature to useEffect",
+ "Runs synchronously between React's DOM mutations and the browser paint",
+ "Blocks paint — keep it fast; avoid async operations",
+ "Use cases: measuring DOM element dimensions, syncing scroll position, tooltip/popover positioning",
+ "Does NOT run on the server (use useEffect or suppress the warning for SSR-safe code)",
+ "Prefer useEffect — only reach for useLayoutEffect when you see visual flicker"
+ ],
+ "resources": [
+ {
+ "title": "useLayoutEffect Reference",
+ "url": "https://react.dev/reference/react/useLayoutEffect"
+ }
+ ]
+ },
+ {
+ "id": "useMemo",
+ "title": "useMemo",
+ "summary": "useMemo memoizes the result of an expensive calculation, recomputing only when its dependencies change. It also provides referential stability for objects and arrays.",
+ "keyPoints": [
+ "const value = useMemo(() => expensiveCalc(a, b), [a, b])",
+ "Does NOT prevent re-renders by itself — pair with React.memo on the child for that",
+ "Primary uses: (1) skip expensive recalculations, (2) stable object/array references for deps",
+ "Memoization has overhead — profile before adding, don't apply everywhere",
+ "The React Compiler can handle most useMemo automatically in the future",
+ "Return value must be deterministic given the same deps"
+ ],
+ "resources": [
+ {
+ "title": "useMemo Reference",
+ "url": "https://react.dev/reference/react/useMemo"
+ }
+ ]
+ },
+ {
+ "id": "useCallback",
+ "title": "useCallback",
+ "summary": "useCallback returns a memoized function reference that only changes when its dependencies change, preventing child components from re-rendering due to new function references.",
+ "keyPoints": [
+ "const fn = useCallback(() => doSomething(a), [a])",
+ "Equivalent to useMemo(() => fn, deps) — syntactic sugar for functions",
+ "Needed when passing callbacks to children wrapped in React.memo",
+ "Needed when a function is listed as a useEffect dependency",
+ "Without useCallback, a new function reference is created on every parent render",
+ "Premature optimization — profile first; the React Compiler will automate this"
+ ],
+ "resources": [
+ {
+ "title": "useCallback Reference",
+ "url": "https://react.dev/reference/react/useCallback"
+ }
+ ]
+ },
+ {
+ "id": "useContext",
+ "title": "useContext",
+ "summary": "useContext reads and subscribes to a React Context, letting components consume a shared value without threading props through every level of the tree.",
+ "keyPoints": [
+ "const value = useContext(MyContext) — returns the nearest Provider's value",
+ "Any value change in the Provider triggers re-render of ALL consumers (no built-in selector)",
+ "Split contexts by update frequency to limit unnecessary re-renders",
+ "Wrap the provided value in useMemo to keep the reference stable",
+ "Context is not a replacement for a global state manager in large apps",
+ "Good for: theme, auth user, locale — low-frequency, broadly needed data"
+ ],
+ "resources": [
+ {
+ "title": "useContext Reference",
+ "url": "https://react.dev/reference/react/useContext"
+ },
+ {
+ "title": "Passing Data Deeply with Context",
+ "url": "https://react.dev/learn/passing-data-deeply-with-context"
+ }
+ ]
+ },
+ {
+ "id": "useRef",
+ "title": "useRef",
+ "summary": "useRef returns a mutable object { current: value } that persists across renders without triggering re-renders. Used for DOM references and storing mutable values.",
+ "keyPoints": [
+ "const ref = useRef(initialValue) — ref.current is the mutable container",
+ "Mutating ref.current does NOT cause a re-render",
+ "DOM refs: → myRef.current is the DOM node",
+ "Mutable storage: interval IDs, previous values, animation frames",
+ "Callback ref: ref={node => { ... }} for setup/teardown on mount/unmount",
+ "Do not read/write ref.current during render — use state for that"
+ ],
+ "resources": [
+ {
+ "title": "useRef Reference",
+ "url": "https://react.dev/reference/react/useRef"
+ },
+ {
+ "title": "Referencing Values with Refs",
+ "url": "https://react.dev/learn/referencing-values-with-refs"
+ }
+ ]
+ },
+ {
+ "id": "useSyncExternalStore",
+ "title": "useSyncExternalStore",
+ "summary": "useSyncExternalStore is the official API for subscribing to external stores (Redux, Zustand, browser APIs) in a way that is safe for concurrent rendering, preventing tearing.",
+ "keyPoints": [
+ "const value = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot?)",
+ "subscribe: function that registers a listener and returns an unsubscribe function",
+ "getSnapshot: synchronously returns the current store value — must be pure and stable",
+ "Prevents 'tearing' where different components read different values during a concurrent render",
+ "Used internally by Redux, Zustand, and other major libraries",
+ "getServerSnapshot: optional, for SSR to avoid hydration mismatches"
+ ],
+ "resources": [
+ {
+ "title": "useSyncExternalStore Reference",
+ "url": "https://react.dev/reference/react/useSyncExternalStore"
+ }
+ ]
+ },
+ {
+ "id": "useTransition",
+ "title": "useTransition",
+ "summary": "useTransition marks state updates as non-urgent transitions, allowing React to keep the UI responsive to urgent updates (user input) while processing the slower update in the background.",
+ "keyPoints": [
+ "const [isPending, startTransition] = useTransition()",
+ "Wrap low-priority state updates: startTransition(() => setTab(next))",
+ "React may interrupt and restart the transition if a higher-priority update comes in",
+ "isPending is true while the transition is in progress — show spinners/skeletons",
+ "Different from debouncing: React still processes the update, just at lower priority",
+ "Use cases: tab switching, large list filtering, any heavy re-render triggered by user input"
+ ],
+ "resources": [
+ {
+ "title": "useTransition Reference",
+ "url": "https://react.dev/reference/react/useTransition"
+ }
+ ]
+ },
+ {
+ "id": "useId",
+ "title": "useId",
+ "summary": "useId generates a unique, stable ID that is consistent between server and client renders — useful for linking accessibility attributes without hydration mismatches.",
+ "keyPoints": [
+ "const id = useId() — generates a string like ':r0:'",
+ "SSR-safe: same ID generated on server and client (no hydration mismatch)",
+ "Do NOT use as list keys — use data IDs for that",
+ "Common pattern: link label to input for a11y —