Laminar Scala.js Library

website·Indexed 33 days ago

https://laminar.dev/

A Scala.js library for building web application interfaces and managing UI state. It includes Airstream for reactive state management and provides tools for rendering DOM elements, handling controlled inputs, and integrating web components.

Tokens
48.8K
Snippets
217
Records
367
Agent score
66%

What's inside Laminar

  1. Overview of the Laminar Scala.js UI Library

    Laminar is a Scala.js library used to build web application interfaces by keeping the UI state in sync with the underlying application state. It is built on the Airstream observables library and the Scala.js platform. Key characteristics include:

    • No Virtual DOM: It operates directly on the DOM without a virtual DOM layer.
    • Native Scala.js: It has no dependencies on JavaScript libraries or JS-specific concepts.
    • Memory Management: It features a unique subscription ownership mechanism for automatic memory safety.
    • Consistency: Airstream is designed to prevent FRP (Functional Reactive Programming) glitches, ensuring consistent state exposure.
  2. Overview of the Laminar Scala.js UI library

    Laminar is a Scala.js library used to build web application interfaces by keeping the UI state in sync with the underlying application state. Unlike many modern UI frameworks, Laminar does not use a virtual DOM and has no dependencies on JavaScript libraries. It is built upon Airstream, a library of observables, and leverages the Scala.js platform to provide a type-safe, expressive environment for UI development.
  3. Understand Airstream Observables in Laminar

    Laminar relies on Airstream for reactivity. There are two primary types of observables:

    • EventStream: A lazy observable representing discrete events in time. It has no concept of a 'current value'.
    • Signal: A lazy observable representing state. It always has a current value and requires an initial value.
  4. Use Laminar Shoelace Web Components

    Laminar Shoelace Bindings v0.1.0 provides type-safe and ergonomic Laminar bindings for Shoelace.js Web Components (e.g., Button, Dropdown, Dialog). These bindings are generated from the Shoelace custom-elements.json manifest with manual adjustments for type accuracy.
  5. Understand Laminar's approach to DOM updates vs Virtual DOM

    Unlike Virtual DOM frameworks (e.g., React) that generate ephemeral virtual subtrees and perform diffing to determine changes, Laminar uses event streams and reactive state variables for precise DOM updates. When a reactive value changes, Laminar updates the specific DOM property directly via the native JavaScript DOM API, bypassing the need for a reconciliation/diffing process. This results in stable references where the lifespan of a ReactiveElement matches the lifespan of the actual DOM element.
  6. Manage reactive state with Airstream

    Airstream is the underlying reactive layer of Laminar. It provides the core primitives for managing asynchronous data flows and state, including Streams, Signals, EventBuses, and StateVars.
  7. Use Laminar Shoelace Web Component bindings

    Laminar Shoelace Bindings v0.1.0 provides type-safe and ergonomic Laminar bindings for Shoelace.js web components (e.g., Button, Dropdown, Dialog). These bindings are generated from the Shoelace custom-elements.json manifest with manual adjustments for full type safety.
  8. Build a full-stack Scala application with Laminar, Waypoint, and ScalaCSS

    The Twotm8 project serves as a comprehensive guide and example for building a Twitter clone using a full-stack Scala architecture. It demonstrates the integration of Laminar for the frontend UI, Waypoint for routing, and ScalaCSS for styling.
    # Source code for the Twotm8 example
    # https://github.com/keynmol/twotm8
  9. Compare Controlled Inputs vs setAsValue

    Use controlled when you need to synchronize the input value from both user input and external observable updates, or when you need to 'undo' invalid input.

    Use setAsValue for simple transformations where you only care about user input and do not need to lock the value to an observable. Note that setAsValue can transform input but cannot 'filter' it (undo invalid characters) because onInput is not cancelable.

    // Uncontrolled transformation using setAsValue
    input(
      placeholder := "Enter zip code: ",
      onInput
        .mapToValue
        .map(_.filter(Character.isDigit))
        .setAsValue --> zipValueObserver
    )