[][src]Crate dodrio_js_api

Implementing dodrio render components with JavaScript.

This crate provides a Rust type JsRender that wraps a JavaScript object with a render method. JsRender implements dodrio::Render by calling its wrapped object's render method to get a JavaScript virtual DOM represented as a tree of JavaScript values. It then converts this tree of JavaScript values into dodrio's normal bump-allocated virtual DOM representation.

This is likely much slower than rendering virtual DOMs directly into the bump allocator from the Rust side of things! Additionally, the shape of the JavaScript virtual DOM is a bit funky and unidiomatic. Keep in mind that this crate exists as a proof of concept for integrating JavaScript components into dodrio -- which is itself also experimental -- and so this crate definitely has some rough edges.


Here is a JavaScript implementation of a rendering component:

class Greeting {
  constructor(who) {
    this.who = who;

  render() {
    return {
      tagName: "p",
      attributes: [
          name: "class",
          value: "greeting",
      listeners: [
          on: "click",
          callback: this.onClick.bind(this),
      children: [
        "Hello, ",
           tagName: "strong",
           children: [this.who],

  async onClick(vdom, event) {
    // Be more excited!
    this.who += "!";

    // Schedule a re-render.
    await vdom.render();

    console.log("re-rendering finished!");

And here is a Rust rendering component that internally uses the JS rendering component:

use dodrio::bumpalo::Bump;
use dodrio::{Node, Render, Vdom};
use dodrio_js_api::JsRender;
use js_sys::Object;
use wasm_bindgen::prelude::*;

extern {
    // Import the JS `Greeting` class.
    #[wasm_bindgen(extends = Object)]
    #[derive(Clone, Debug)]
    type Greeting;

    // And the `Greeting` class's constructor.
    fn new(who: &str) -> Greeting;

/// This is our Rust rendering component that wraps the JS rendering component.
pub struct GreetingViaJs {
    js: JsRender,

impl GreetingViaJs {
    /// Create a new `GreetingViaJs`, which will internally create a new JS
    /// `Greeting`.
    pub fn new(who: &str) -> GreetingViaJs {
        let js = JsRender::new(Greeting::new(who));
        GreetingViaJs { js }

/// And finally the `Render` implementation! This adds a `<p>` element and some
/// text around whatever the inner JS `Greeting` component renders.
impl Render for GreetingViaJs {
    fn render<'a, 'bump>(&'a self, bump: &'bump Bump) -> Node<'bump>
        'a: 'bump,
        use dodrio::builder::*;
                text("JavaScript says: "),



A rendering component implemented in JavaScript.


A weak handle to a virtual DOM.