Overview
A few small, broadly-useful Vue composables for AbsoluteJS (SSR-first) apps. Vue is a peer dependency.
@absolutejs/vue-composablesv0.3.3betaFrontend & UXSmall SSR-aware Vue composables — hydration gate, browser flag, debounced actions, and an async try/catch/notify wrapper — for Vue 3 apps.
@absolutejs/vue-composables is a small set of broadly-useful Vue composables for SSR-first apps: an SSR hydration gate, a browser-environment flag, a scope-safe debouncer, and an async-action wrapper that centralizes try/catch, loading flags, and toast notifications. Vue is a peer dependency, so it drops into any Vue 3 app — including AbsoluteJS Vue pages — without pulling in a second Vue copy.
bun add @absolutejs/vue-composablesA few small, broadly-useful Vue composables for AbsoluteJS (SSR-first) apps. Vue is a peer dependency.
useHydrated() — a ref that's false during SSR + the first client
render, then true after mount. Gate client-only data on it to avoid hydration mismatches: loading = !hydrated.value || actualLoading.value.
isBrowser — true on the client, false during SSR.
useDebouncedAction(fn, delayMs?) — trailing-edge debouncer auto-cleared
on scope dispose; .trigger() (re)starts the delay.
useResizeObserver(target, callback, options?) — SSR-safe element
observer that coalesces notifications to the next animation frame and automatically cleans up when the target or Vue scope changes.
useAutoGrowTextarea(target, { maxHeight }) — keeps chat composers
content-sized until a reactive maximum, then switches to internal scrolling.
isTextSubmitKey(event) — recognizes plain Enter while excluding
Shift+Enter and IME composition confirmation.
runAsyncAction(task, options) — the try/catch/finally + notify +
console.error + loading-flag wrapper. Inject your toast once with configureAsyncNotifier({ success, error }).
Apache-2.0
useHydrated returns a ref that is false during SSR and the first client render, then true after mount — gate client-only data on it to avoid hydration mismatches.
isBrowser is true on the client and false during SSR, for quick environment checks outside component setup.
useDebouncedAction gives a trailing-edge debouncer whose timer is auto-cleared on scope dispose; trigger() restarts the delay.
runAsyncAction wraps a task with try/catch/finally, a loading-flag callback, console.error, and success/error notifications.
configureAsyncNotifier injects your toast implementation once, so every runAsyncAction call site stays free of notification plumbing.
Outcomes
A few small, broadly-useful Vue composables for AbsoluteJS (SSR-first) apps. Vue is a peer dependency.
useHydrated() — a ref that's false during SSR + the first client
Apache-2.0
Hardening checklist
Follow in order
Working example for Async actions.
import {
configureAsyncNotifier,
runAsyncAction,
useHydrated
} from '@absolutejs/vue-composables';
configureAsyncNotifier({ success: toast.success, error: toast.error });
await runAsyncAction(() => api.save(payload), {
successMessage: 'Saved',
loading: (s) => (saving.value = s),
onSuccess: () => emit('updated')
});Working example for Resize observation.
const panel = useTemplateRef<HTMLElement>('panel');
useResizeObserver(panel, ([entry]) => {
if (entry) compact.value = entry.contentRect.width < 640;
});Wire the notifier once, run async actions without repeated try/catch/loading boilerplate, and gate client-only state on hydration.
import {
configureAsyncNotifier,
runAsyncAction,
useHydrated
} from '@absolutejs/vue-composables';
import { computed } from 'vue';
// Inject your toast once, app-wide
configureAsyncNotifier({ error: toast.error, success: toast.success });
await runAsyncAction(() => api.save(payload), {
loading: (s) => (saving.value = s),
onSuccess: () => emit('updated'),
successMessage: 'Saved'
});
// Gate client-only data to avoid hydration mismatches
const hydrated = useHydrated();
const loading = computed(() => !hydrated.value || actualLoading.value);Debounce user input without managing timers — cleanup happens automatically on scope dispose.
import { useDebouncedAction } from '@absolutejs/vue-composables';
// Trailing-edge debounce, auto-cleared when the component scope disposes
const search = useDebouncedAction(() => {
void fetchResults(query.value);
}, 250);
// Each call (re)starts the delay
const onInput = () => search.trigger();Current package surface