import { addEventListeners, css, on, ref, TypedEventTarget, type Handle, type RemixNode, } from '@remix-run/ui' // ============================================================================ // Getting Started - Basic App Example // ============================================================================ function App(handle: Handle) { let count = 0 return () => ( ) } // ============================================================================ // Component State and Updates - Counter // ============================================================================ function Counter(handle: Handle) { let count = 0 return () => (
Count: {count}
) } // ============================================================================ // Components - Greeting // ============================================================================ function Greeting(handle: Handle<{ name: string }>) { return () =>

Hello, {handle.props.name}!

} // ============================================================================ // Stateful Components - CounterWithSetup // ============================================================================ function CounterWithSetup(handle: Handle<{ initialCount: number; label?: string }>) { // Component function: runs once let count = handle.props.initialCount // Return render function: runs on every update return () => (
{handle.props.label || 'Count'}: {count}
) } // ============================================================================ // Setup Prop vs Props - CounterWithLabel // ============================================================================ function CounterWithLabel(handle: Handle<{ initialCount: number; label?: string }>) { let count = handle.props.initialCount return () => (
{handle.props.label}: {count}
) } // ============================================================================ // Events - SearchInput // ============================================================================ function SearchInput(handle: Handle) { let query = '' let results: string[] = [] let loading = false return () => (
{ query = event.currentTarget.value loading = true handle.update() // Simulated search with timeout setTimeout(() => { if (signal.aborted) return results = query ? [`Result for "${query}" 1`, `Result for "${query}" 2`] : [] loading = false handle.update() }, 300) }), ]} /> {loading &&
Loading...
} {!loading && results.length > 0 && ( )}
) } // ============================================================================ // Controlled Input - Slug Form // ============================================================================ function SlugForm(handle: Handle) { let slug = '' let generatedSlug = '' return () => (
) } // ============================================================================ // Global Events - KeyboardTracker // ============================================================================ function KeyboardTracker(handle: Handle) { let keys: string[] = [] addEventListeners(document, handle.signal, { keydown: (event) => { keys.push(event.key) if (keys.length > 10) keys.shift() handle.update() }, }) return () =>
Keys: {keys.join(', ') || '(press some keys)'}
} // ============================================================================ // CSS Prop - Button (Basic) // ============================================================================ function ButtonBasic() { return () => ( ) } // ============================================================================ // CSS Prop - Button (Advanced with nested rules) // ============================================================================ function ButtonAdvanced() { return () => ( ) } // ============================================================================ // Ref Mixin - Form (Basic) // ============================================================================ function FormBasic() { let inputRef: HTMLInputElement return () => (
(inputRef = node)), css({ marginRight: '8px', padding: '4px 8px' })]} />
) } // ============================================================================ // Ref Mixin with AbortSignal - ResizeObserver Component // ============================================================================ function ResizeComponent(handle: Handle) { let dimensions = { width: 0, height: 0 } return () => (
{ // Set up something that needs cleanup let observer = new ResizeObserver((entries) => { let entry = entries[0] if (entry) { dimensions.width = Math.round(entry.contentRect.width) dimensions.height = Math.round(entry.contentRect.height) handle.update() } }) observer.observe(node) // Clean up when element is removed signal.addEventListener('abort', () => { observer.disconnect() }) }), css({ padding: '20px', backgroundColor: 'rgba(255, 255, 255, 0.1)', borderRadius: '8px', resize: 'both', overflow: 'auto', minWidth: '100px', minHeight: '60px', border: '1px solid rgb(209, 213, 219)', }), ]} > Resize me! ({dimensions.width} × {dimensions.height})
) } // ============================================================================ // handle.update() - Player // ============================================================================ function Player(handle: Handle) { let isPlaying = false let playButton: HTMLButtonElement let stopButton: HTMLButtonElement return () => (
) } // ============================================================================ // handle.queueTask - Form with scroll // ============================================================================ function FormWithScroll(handle: Handle) { let showDetails = false let detailsSection: HTMLElement return () => (
{showDetails && (
(detailsSection = node)), css({ marginTop: '1rem', padding: '1rem', border: '1px solid rgba(255, 255, 255, 0.2)', borderRadius: '8px', backgroundColor: 'rgba(255, 255, 255, 0.05)', }), ]} >

Additional Details

This section appears when the checkbox is checked.

)}
) } // ============================================================================ // handle.signal - Clock // ============================================================================ function Clock(handle: Handle) { let interval = setInterval(() => { // clear the interval when the component is disconnected if (handle.signal.aborted) { clearInterval(interval) return } handle.update() }, 1000) return () => {new Date().toLocaleTimeString()} } // ============================================================================ // handle.id - LabeledInput // ============================================================================ function LabeledInput(handle: Handle) { return () => (
) } // ============================================================================ // Context API - Theme Provider and Consumer // ============================================================================ function ThemeProvider(handle: Handle<{}, { theme: string }>) { handle.context.set({ theme: 'dark' }) return () => (
) } function ThemedHeader(handle: Handle) { // Consume context from ThemeProvider let { theme } = handle.context.get(ThemeProvider) return () => (
Header
) } // ============================================================================ // Context API with EventTarget - Advanced Theme // ============================================================================ class Theme extends TypedEventTarget<{ change: Event }> { #value: 'light' | 'dark' = 'light' get value() { return this.#value } setValue(value: 'light' | 'dark') { this.#value = value this.dispatchEvent(new Event('change')) } } function ThemeProviderAdvanced(handle: Handle<{}, Theme>) { let theme = new Theme() handle.context.set(theme) return () => (
) } function ThemedContent(handle: Handle) { let theme = handle.context.get(ThemeProviderAdvanced) // Subscribe to theme changes and update when it changes addEventListeners(theme, handle.signal, { change() { handle.update() }, }) return () => (
Current theme: {theme.value}
) } // ============================================================================ // Fragments - List // ============================================================================ function ListWithFragment() { return () => ( ) } // ============================================================================ // Example Container Component // ============================================================================ function Example(handle: Handle<{ title: string; children: RemixNode }>) { return () => (

{handle.props.title}

{handle.props.children}
) } // ============================================================================ // Main Demo App // ============================================================================ /** * @name README Examples * @description A gallery of small examples that mirror the package README snippets. */ export default function DemoApp() { return () => (
) }