lustre/portal

A portal changes the physical placaement of its children in the DOM, while keeping them logically inside your Lustre app. This makes it possible to implement things like modals and tooltips that typically need to be rendered outside of the app root to ensure they properly overlay other elements.

Types

It’s possible for the portal to fail when teleporting its children for a number of reasons. If that happens, the element will emit an "error" event with details on what went wrong.

pub type Error {
  MissingSelector
  InvalidSelector(selector: String)
  TargetNotFound(selector: String)
  TargetInsideLustre(selector: String)
  TargetIsCrossOriginIframe(selector: String)
  TargetIsPortal(selector: String)
}

Constructors

  • MissingSelector

    The portal’s "target" attribute was missing or empty.

  • InvalidSelector(selector: String)

    The portal’s "target" attribute was not a valid CSS selector.

  • TargetNotFound(selector: String)

    No element could be found matching the portal’s "target" attribute.

  • TargetInsideLustre(selector: String)

    An element was found matching the portal’s "target" attribute, but it is “owned” by Lustre. Teleporting this portal’s children to it would conflict with Lustre’s virtual DOM and cause unexpected behaviour.

  • TargetIsCrossOriginIframe(selector: String)

    The portal’s "target" attribute points to an iframe but that iframe’s source is from a different origin. The portal can only teleport children into an iframe when the iframe is from the same origin as your Lustre app.

  • TargetIsPortal(selector: String)

    The portal’s "target" attribute points to another portal element. This might lead to elements being teleported back and forth between multiple portals, causing runtime errors and unexpected behaviour.

The root element the portal will use to find the target element. This is used with the root attribute to better control where the portal’s children will be teleported to.

pub type Root {
  Document
  Relative
}

Constructors

  • Document

    Use the document root, meaning the portal will use document.querySelector to find the target element. This is the default behaviour and in most cases is what you want.

  • Relative

    Use the nearest root node in the DOM as the basis for the query. This is found by calling getRootNode() on the portal element itself, and is useful in cases where the portal is rendered inside another Lustre component.

Values

pub fn error_decoder() -> decode.Decoder(Error)

Decode the detail of a portal’s "error" event. You might use this decoder if you’re writing your own event handler instead of the provided one.

pub const name: String

The name of the <lustre-portal> custom element. You might use this if you’re rendering the element yourself or if you want to check if the component has already been registered.

pub fn on_error(
  handler: fn(Error) -> msg,
) -> @internal Attribute(msg)

A portal could fail for a number of reasons. When it does, it will emit an "error" event with some information on what went wrong. You might use this event listener to log errors in something like Sentry, or recover your ui if something important could not be teleported.

pub fn register() -> Result(Nil, lustre.Error)

Register the <lustre-portal> component. If you have not included the standalone JavaScript bundle in your HTML document, it’s typical to call this function before you start your Lustre application.

Note: this function is only meaningful when running in the browser and will produce a NotABrowser error if called on the server. If you want to use portals in server components or in server-rendered HTML, you should include the pre-built JavaScript bundle found in priv/static/lustre-portal.min.mjs or embed the inline script using the script function.

pub fn root(root: Root) -> @internal Attribute(msg)

The "root" attribute determines how the portal will find the target element. By default, the portal will use the Document root, meaning queries for the target element will use document.querySelector.

Alternatively, you can set the root to Relative, which will cause the portal to use the nearest root node in the DOM as the basis for the query. This can be useful if you’re rendering the portal inside another Lustre component and want to ensure the portal’s children don’t escape the component’s shadow DOM.

pub fn script() -> @internal Element(msg)

Inline the portal component script as a <script> tag. Where possible you should prefer using register in an SPA, or serving the pre-built client runtime from lustre_portal’s priv/static directory when using server-components.

This inline script can be useful for development or scenarios where you don’t control the HTML document.

pub fn to(
  target selector: String,
  with attributes: List(@internal Attribute(msg)),
  teleport children: List(@internal Element(msg)),
) -> @internal Element(msg)

Render a portal, teleporting all children to another element in the DOM outside of Lustre’s control. The target must be a valid CSS selector, and the first element matching that selector will be used as the target to teleport the children to.

Search Document