DOM Utilities
@praxisjs/composables DOM composable classes — WindowSize, ScrollPosition, ElementSize, Intersection, and Focus. Used via the @Compose decorator.
DOM Utilities
DOM composables from @praxisjs/composables. Attach them to any component with @Compose to bind reactive DOM state directly to component properties.
npm install @praxisjs/composablespnpm add @praxisjs/composablesyarn add @praxisjs/composablesbun add @praxisjs/composablesWindowSize
Tracks the browser window's inner dimensions reactively. Updates on every resize event.
import { Compose, Ref } from '@praxisjs/decorators'
import { WindowSize } from '@praxisjs/composables'
@Component()
class App extends StatefulComponent {
@Compose(WindowSize)
window!: WindowSize
render() {
return (
<div>
<p>Viewport: {() => this.window.width} × {() => this.window.height}</p>
{() => this.window.width < 768 && <MobileMenu />}
</div>
)
}
}Properties: width: number, height: number
ScrollPosition
Tracks scroll position. Omit the argument to track the window scroll; pass a ref string to track a specific scrollable element.
// Track window scroll
@Compose(ScrollPosition)
scroll!: ScrollPosition
render() {
return <p>Scroll Y: {() => this.scroll.y}px</p>
}// Track a specific scrollable element
@Ref<HTMLDivElement>()
containerRef!: Ref<HTMLDivElement>
@Compose(ScrollPosition, 'containerRef')
scroll!: ScrollPosition
render() {
return (
<div
ref={this.containerRef}
style="height:300px;overflow:auto"
>
<p>Scroll: {() => this.scroll.y}px</p>
{/* scrollable content */}
</div>
)
}Pass the ref name as a string
Pass the property name as a string ('containerRef') to @Compose. The element doesn't exist at decoration time — the string is resolved to the Ref object at mount when the DOM is ready.
Properties: x: number, y: number
ElementSize
Tracks an element's dimensions reactively via ResizeObserver. Updates whenever the element's size changes.
@Component()
class ResizeWatcher extends StatefulComponent {
@Ref<HTMLDivElement>()
containerRef!: Ref<HTMLDivElement>
@Compose(ElementSize, 'containerRef')
size!: ElementSize
render() {
return (
<div ref={this.containerRef}>
<p>Width: {() => this.size.width}px, Height: {() => this.size.height}px</p>
</div>
)
}
}Properties: width: number, height: number
Intersection
Tracks whether an element is intersecting the viewport (or a scroll container) via IntersectionObserver.
@Component()
class LazySection extends StatefulComponent {
@Ref<HTMLElement>()
sectionRef!: Ref<HTMLElement>
@Compose(Intersection, 'sectionRef', { threshold: 0.5 })
visibility!: Intersection
render() {
return (
<section ref={this.sectionRef}>
{() => this.visibility.visible ? <HeavyContent /> : <Placeholder />}
</section>
)
}
}Constructor: new Intersection(ref, options?) — options matches IntersectionObserverInit.
Properties: visible: boolean
Focus
Tracks whether an element currently has focus.
@Component()
class SearchBar extends StatefulComponent {
@Ref<HTMLInputElement>()
inputRef!: Ref<HTMLInputElement>
@Compose(Focus, 'inputRef')
focus!: Focus
render() {
return (
<div>
<input ref={this.inputRef} placeholder="Search..." />
{() => this.focus.focused && <span class="hint">Press Enter to search</span>}
</div>
)
}
}Properties: focused: boolean