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 usedocument.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 inpriv/static/lustre-portal.min.mjs
or embed the inline script using thescript
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.