Files
2026-01-13 02:42:58 +01:00

2.0 KiB

Blockers (Website UX)

This document defines Blockers as UX-only prevention mechanisms in the website.

IMPORTANT: Blockers are optional UX helpers. They are NOT enforced by ESLint rules and do not belong in the strict architecture contract.

Shared contract: docs/architecture/shared/BLOCKERS_AND_GUARDS.md

1) Definition

A Blocker is a website mechanism that prevents an action from being executed.

Blockers exist solely to improve UX and reduce unnecessary requests.

Blockers are not security. They are best-effort helpers that can be bypassed.

2) Purpose

Use Blockers to:

  • Prevent multiple form submissions
  • Debounce rapid button clicks
  • Temporarily disable actions during loading
  • Show/hide UI elements based on state

Do NOT use Blockers for:

  • Authorization checks
  • Security enforcement
  • Permanent access control

3) Placement

Since Blockers are UX-only, they belong in:

  • apps/website/components/** (component-specific blockers)
  • apps/website/hooks/** (shared blocker hooks)
  • apps/website/utils/** (blocker utilities)

NOT in lib/ - lib/ is for business logic and architecture contracts.

4) Example

// ✅ OK: Component-level blocker
export function useSubmitBlocker() {
  const [isSubmitting, setIsSubmitting] = useState(false);
  
  return {
    isSubmitting,
    block: () => setIsSubmitting(true),
    release: () => setIsSubmitting(false),
  };
}

// Usage
const blocker = useSubmitBlocker();

async function handleSubmit() {
  if (blocker.isSubmitting) return;
  
  blocker.block();
  await submitForm();
  blocker.release();
}

5) Key Principle

Blockers are optional. The backend must never rely on them.

If a blocker prevents a submission, the backend should still:

  • Validate the request
  • Return appropriate errors
  • Handle duplicate submissions gracefully

This is why Blockers don't need ESLint enforcement - they're just UX sugar.