Skip to content

Web

onEvent

Integrates external event sources (DOM elements, WebSockets, etc.) with Reatom’s reactive system and abort context.

Can be used in two ways:

  1. As a Promise (without callback): Returns a promise that resolves when the

event fires once. Use with await wrap(onEvent(...)) in actions to wait for events while respecting abort contexts.

  1. As a Subscription (with callback): Registers a callback that fires on

each event occurrence. Returns an unsubscribe function for cleanup.

When used within an action with abort context, onEvent automatically cleans up listeners when the action is aborted or when a component unmounts, preventing memory leaks and stale event handlers.

Example 1

import { action, onEvent, wrap } from '@reatom/core'
const handleUserAction = action(async () => {
const button = document.getElementById('confirmButton')
const clickEvent = await wrap(onEvent(button, 'click'))
console.log(clickEvent.clientX, clickEvent.clientY)
processUserConfirmation()
}, 'handleUserAction').extend(withAbort())

Example 2

import { atom, effect, onEvent } from '@reatom/core'
const activeVideoAtom = atom(null, 'activeVideo')
const videoStatsAtom = atom({ plays: 0, pauses: 0 }, 'videoStats')
effect(() => {
const videoElement = activeVideoAtom()
if (!videoElement) return
// the listener will be cleared automatically, when the new videoElement is set
onEvent(videoElement, 'play', () => {
videoStatsAtom.set((stats) => ({ ...stats, plays: stats.plays + 1 }))
})
onEvent(videoElement, 'pause', () => {
videoStatsAtom.set((stats) => ({
...stats,
pauses: stats.pauses + 1,
}))
})
})

reatomMediaQuery

Creates a reactive atom that tracks a CSS media query state.

The atom automatically updates when the media query match state changes, providing a reactive way to respond to viewport changes, dark mode preferences, and other media features.

Example 1

const isMobile = reatomMediaQuery('(max-width: 767px)')
const isPrint = reatomMediaQuery('print')

Example 2

const isDarkModeMedia = reatomMediaQuery('(prefers-color-scheme: dark)')
const themeAtom = reatomEnum(
['light', 'dark', 'system'],
'themeAtom',
).extend(
withComputed((state) => {
if (state === 'system') return isDarkModeMedia() ? 'dark' : 'light'
return state
}),
withLocalStorage('theme'),
withChangeHook((state) => {
if (state === 'system') {
document.body.classList.remove('light', 'dark')
} else {
document.body.classList.toggle('dark', state === 'dark')
}
}),
)