stacksjs

stacks-composables

Use when choosing or implementing reactive composables in STX, data queries, forms, consent, browser APIs, motion, or debugging client delivery. Covers @stacksjs/composables, STX eager and demand browser delivery, and the difference between callable signals and module Refs.

stacksjs 636 20 Updated 2w ago

Resources

1
GitHub

Install

npx skillscat add stacksjs/stacks/stacks-composables

Install via the SkillsCat registry.

SKILL.md

Stacks composables

Choose the execution surface before copying a composable signature. An STX
client script, an explicitly imported @stacksjs/composables module, and a
server script can expose similarly named functions with different contracts.
Read BROWSER.md for template delivery, forms and motion examples.

Eager window aliases

The following markers describe only explicit eager window.name aliases in
getCachedSignalsRuntime(). They are checked by
core/composables/tests/skill-runtime-globals.test.ts, and are not the whole
compiler-delivered client surface.

useAsync, useClickOutside, useColorMode, useCounter, useDark,
useDebounce, useDebouncedValue, useEventListener, useFetch, useFocus,
useHead, useInterval, useLocalStorage, useMutation, useQuery,
useRef, useRoute, useSearchParams, useSeoMeta, useSessionStorage,
useStore, useThrottle, useTimeout, useToggle, useWebSocket.

Additional STX names are exposed through window.stx and compiler
destructuring, or bundled from STX composables on demand. In current STX,
useMediaQuery and usePreferredReducedMotion use the first path;
useForm, useScroll, useMouse, useParallax, and
useIntersectionObserver use the demand path. These client-script names do
not come from the ambient browser-auto-imports.json manifest.

Explicit module imports

The module surface lives in core/composables/src/index.ts. Import every
binding in a TypeScript module even if a template entry can use it bare.

import { useCounter } from '@stacksjs/composables'

const counter = useCounter(0, { min: 0, max: 10 })
counter.inc()
const value = counter.count.value

Module composables use object Ref values from STX: read/write .value,
subscribe where provided, and use the exported cleanup/control functions.
Template signals use count(), .set(), and .update(). Passing a callable
signal into a module helper expecting a Ref is not an implicit conversion.

Task Explicit module exports
State/storage useCounter, useToggle, useStorage, useLocalStorage, history helpers
Async/data useFetch, createFetch, useQuery, useMutation, createQueryClient, useAsyncState
Forms/consent useForm, useCookieConsent
DOM/input useFocus, useEventListener, onClickOutside, observers, useScroll, useMouse
Timing/watch useIntervalFn, useTimeoutFn, useTimeoutPoll, watchDebounced, watchPausable
Media/device useMediaQuery, usePreferredReducedMotion, useGeolocation, useDeviceOrientation
Browser facilities clipboard, permissions, fullscreen, workers, virtual lists, sharing

Inspect the barrel and the individual implementation for other exports rather
than installing a second library for a feature Stacks already has.

Module query cache

useQuery({ queryKey, queryFn, staleTime, enabled, client }) provides Ref
data/error/loading state, in-flight deduplication and refetch().
queryFn receives an AbortSignal. createQueryClient({ gcTime }) provides
scoped clients, get, set, invalidate, gc, and clear.
Invalidation accepts prefix keys or a predicate matcher. Optional
refetchOnFocus and refetchOnReconnect refetch stale data. Use
unsubscribe() when the consumer ends. For template runtime queries read
the STX contract in BROWSER.md; their signatures differ.

Module forms and consent

Explicit useForm({ initialValues, schema, onSubmit, validateOn }) accepts
Stacks validators, exposes Ref values plus field(name) accessors, dirty/touched
state, accessible inputProps(), submitButtonProps(), and server-error
setErrors(). Apply a returned 422 map explicitly; fetching an error does
not automatically attach it to a form. Field arrays and a progressive HTML
fallback are not established by the primitive alone.

useCookieConsent({ policyVersion, storageKey, onChange }) stores a versioned
decision. Necessary consent is always enabled; optional categories default to
declined. accept, acceptAll, declineAll, and withdraw change it;
allows(category) gates loading. A changed policy version asks again, blocked
storage falls back to no stored decision, and returned visitor consent is
independent of a signed-in session. Import this helper explicitly.

Gotchas

  • Browser capability availability and permission denial are runtime states,
    even when a helper imports successfully during SSR.
  • Client observers/listeners need teardown. Read the selected helper's return
    shape; stop, remove, and unsubscribe are not interchangeable names.
  • Module useTimeout(ms) returns a Ref unless controls are requested; browser
    runtime useTimeout(callback, delay) runs a callback. Module counter methods
    are inc/dec, never increment/decrement.
  • Typechecking an ambient name proves neither its delivery nor its contract.
    Exercise a rendered template with the installed STX version.

Source and evidence

core/composables/src/index.ts, individual source files, and retained
tests/use-query.test.ts, tests/use-form.test.ts,
tests/use-cookie-consent.test.ts and tests/skill-runtime-globals.test.ts
are authoritative (core paths relative to storage/framework/).