Skip to content
Back to skills

Hook

ASecurity

Create a reusable React hook (useX). Triggers "create hook", "new hook", "custom hook", a useX-style name, or extracting logic out of a component.

  • 47 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added February 7, 2026
developmentreactnextjsapidocumentation

Works with

  • cli
  • api
  • mcp

Security analysis

A100/100

Scanned September 29, 2026

npx -y skills add darkroomengineering/cc-settings --skill hook --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Hook?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Hook
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/darkroomengineering-hook/badge)](https://www.skillsdirectory.com/skills/darkroomengineering-hook)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: hook
description: Create a reusable React hook (useX). Triggers "create hook", "new hook", "custom hook", a useX-style name, or extracting logic out of a component.
argument-hint: "[hookName]"
---

# Create Custom Hook

Create a custom React hook following Darkroom conventions. The hook itself is stack-agnostic — what differs between satus and novus is the path alias.

## Step 1 — Check existing abstractions

Apply the Laziness Ladder before scaffolding, even when the request proposes a
hook name. Search project hooks, utilities, and callers by behavior and related
terms; read matching implementations to check their contract and import path.
Prefer a matching project hook, including wrappers around `hamo`, over direct
dependency calls or a new wrapper. If one fits, use it and stop here.

For example, in Satus, search for `useDeviceDetection`, `isDesktop`, and media-query
usage before adding `useIsDesktop` or repeating a breakpoint string. When the local
contract matches the requirement, use `const { isDesktop } = useDeviceDetection()`
with the verified local import. Check breakpoint semantics and server/initial
render behavior; do not assume every media query means the same thing.

If no project abstraction fits, check runtime/platform APIs and installed
dependencies. For common hook behavior, check installed `hamo` hooks using the
documentation procedure below. Before creating a hook, name the implementations
checked and the behavior they lack; then continue only for that gap.

## Step 2 — Detect stack

Read `package.json`:
- `dependencies.next` → satus / Next.js (path alias `@/`, hooks require a `'use client'` boundary)
- `dependencies["react-router"]` → novus / React Router (path alias `~/`, components isomorphic)

## Step 3 — Choose location

| Stack | Hook path |
|---|---|
| satus | `lib/hooks/<name>.ts` |
| novus | `hooks/<name>.ts` (novus puts `hooks/` at the project root) |

Confirm by checking the existing `lib/hooks/` or `hooks/` directory structure if either pattern is unclear from package.json alone.

## Step 4 — Emit template

### satus / Next.js
```tsx
// lib/hooks/<name>.ts
'use client'
// Client Components can prerender on the server. Read browser APIs in effects
// or event handlers, with the same initial state on the server and browser.

import { useState, useEffect } from 'react'

interface Use<Name>Options {
  // Hook configuration options
}

interface Use<Name>Return {
  // Return type definition
}

export function use<Name>(options?: Use<Name>Options): Use<Name>Return {
  // Implementation
  return {
    // Return values
  }
}
```

### novus / React Router
```tsx
// hooks/<name>.ts
// No 'use client' — RR components are isomorphic; the hook runs wherever
// it's called from. Read browser APIs in effects or event handlers, with the
// same initial state on the server and browser.

import { useState, useEffect } from 'react'

interface Use<Name>Options {
  // Hook configuration options
}

interface Use<Name>Return {
  // Return type definition
}

export function use<Name>(options?: Use<Name>Options): Use<Name>Return {
  // Implementation
  return {
    // Return values
  }
}
```

## Conventions (both stacks)

1. **Type everything** — options interface, return interface.
2. **Named export** — `export function useX`, not default.
3. **Prefix with `use`** — React hook naming convention.
4. **No memoization** — React Compiler handles it automatically.
5. **Hydration-safe state** — both stacks can render on the server. Use a
   deterministic initial value for the server render and first browser render;
   `'use client'` does not disable prerendering. A `typeof window` branch in a
   lazy state initializer can still produce different markup and a hydration
   mismatch. Read `localStorage` in an effect, and finish that read before
   enabling an effect that persists state, so initial defaults cannot overwrite
   stored values.

## Stack-specific

| | satus | novus |
|---|---|---|
| Directive | `'use client'` (hooks live in client boundary) | None (isomorphic) |
| Browser APIs | SSR-safe initial state; effects or event handlers | SSR-safe initial state; effects or event handlers |
| Path alias | `@/` | `~/` |

## Before you start

If this hook uses an external library, **fetch docs first**:
1. Use Context7 MCP (`mcp__context7__resolve-library-id` → `get-library-docs`) in Claude or when the user configured it in standalone Codex. Otherwise use official docs through native browsing or inspect the pinned local package. cc-settings does not auto-run unpinned registry MCP packages in Codex.
2. Run `bun info <package>` to check the latest version.

## Example

```
User: "create a useLocalStorage hook" (in satus repo)
→ Checks project hooks, platform APIs, and installed dependencies first; only for an uncovered gap, creates lib/hooks/use-local-storage.ts with 'use client', deterministic initial state, effect-based storage read before writes

User: "create a useLocalStorage hook" (in novus repo)
→ Checks project hooks, platform APIs, and installed dependencies first; only for an uncovered gap, creates hooks/use-local-storage.ts, no directive, deterministic initial state, effect-based storage read before writes
```

## Arguments

- `$ARGUMENTS` — Hook name (e.g., "useAuth", "useLocalStorage")

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.