Browser APIs
Browser API composables from @praxisjs/composables. Bind them to components with @Compose.
npm install @praxisjs/composablespnpm add @praxisjs/composablesyarn add @praxisjs/composablesbun add @praxisjs/composablesMediaQuery
Reactive CSS media query matching.
@Compose(MediaQuery, '(max-width: 768px)')
mobile!: MediaQuery
render() {
return () => this.mobile.matches ? <MobileView /> : <DesktopView />
}Constructor: new MediaQuery(query: string) Properties: matches: boolean
ColorScheme
Detects the user's preferred color scheme.
@Compose(ColorScheme)
scheme!: ColorScheme
render() {
return <div class={() => this.scheme.isDark ? 'dark' : 'light'}>...</div>
}Properties: isDark: boolean, isLight: boolean
Mouse
Tracks the cursor position in the viewport.
@Compose(Mouse)
mouse!: Mouse
render() {
return <p>x: {() => this.mouse.x}, y: {() => this.mouse.y}</p>
}Properties: x: number, y: number
KeyCombo
Detects keyboard shortcut combinations.
@Compose(KeyCombo, 'ctrl+s')
saveShortcut!: KeyCombo
onMount() {
effect(() => {
if (this.saveShortcut.pressed) this.save()
})
}Constructor: new KeyCombo(combo: string) — accepts ctrl, shift, alt, meta modifiers. Properties: pressed: boolean
Idle
Detects user inactivity. Default timeout is 60 seconds.
@Compose(Idle, 30_000)
activity!: Idle
render() {
return () => this.activity.idle ? <ScreenSaver /> : <AppContent />
}Constructor: new Idle(timeout?: number) — timeout in ms. Properties: idle: boolean
Clipboard
Read/write clipboard access. copied resets to false after resetDelay ms (default: 2000).
@Compose(Clipboard)
clipboard!: Clipboard
render() {
return (
<button onClick={() => this.clipboard.copy('Hello!')}>
{() => this.clipboard.copied ? 'Copied!' : 'Copy'}
</button>
)
}Properties: copied: boolean, content: string, copy(text): Promise<void>
Geolocation
One-shot geolocation lookup.
@Compose(Geolocation, { enableHighAccuracy: true })
geo!: Geolocation
render() {
return (
<div>
{() => this.geo.loading && <p>Locating...</p>}
{() => this.geo.error && <p>Location denied</p>}
{() => !this.geo.loading && !this.geo.error && (
<p>Lat: {this.geo.lat}, Lon: {this.geo.lng}</p>
)}
</div>
)
}Constructor: new Geolocation(options?: PositionOptions) Properties: lat: number | null, lng: number | null, error: GeolocationPositionError | null, loading: boolean
TimeAgo
Relative time formatting, updated every minute.
@State() postedAt = new Date('2026-01-01')
@Compose(TimeAgo, 'postedAt')
timeAgo!: TimeAgo
render() {
return <p>Posted {() => this.timeAgo.value}</p>
// → "3 months ago"
}Constructor: new TimeAgo(source: Signal<Date> | (() => Date), locale?: string) Properties: value: string
Pagination
Pagination state management.
@Compose(Pagination, { total: 100, pageSize: 10 })
pages!: Pagination
render() {
return (
<div>
<p>Page {() => this.pages.page} of {() => this.pages.totalPages}</p>
<button disabled={() => !this.pages.hasPrev} onClick={() => this.pages.prev()}>Prev</button>
<button disabled={() => !this.pages.hasNext} onClick={() => this.pages.next()}>Next</button>
</div>
)
}Constructor: new Pagination({ total, pageSize, initial? })
| Property | Description |
|---|---|
page | Current page (1-based) |
totalPages | Total number of pages |
offset | Items to skip (for slice/API calls) |
hasPrev / hasNext | Navigation availability |
prev() / next() | Navigate pages |
goTo(n) | Jump to page n |
first() / last() | Jump to first/last page |