Reactive Feed

This example demonstrates prepend and append behavior using reusable DOM node references.

Each post is a stateful DOM element. Posts preserve local identity, event listeners, and runtime ownership while being reordered.

Important

DOM++ does not perform hidden list reconciliation.

Feed behavior is driven entirely by:

Feed Runtime Pattern

// =====================================
// ID
// =====================================
let nextId = 1;

// =====================================
// FEED DATA
// =====================================
let posts = [];

// =====================================
// FEED ROOT
// =====================================
const feed =
  document
    .createElement("div")
    .setAttributes({
      class: "feed"
    });

// =====================================
// RENDER
// =====================================
function renderFeed() {
  feed.setChildren(
    ...posts
  );
}

// =====================================
// CREATE POST
// =====================================
function createPost(text) {
  const id =
    nextId++;

  // ===================================
  // ELEMENT REFERENCE
  // ===================================
  const post =
    document
      .createElement("div")
      .setAttributes({
        class: "post"
      })
      .setState({
        text,
        edits: 0
      })
      .setChildren(({
        state,
        setState
      }) => [
        // =============================
        // HEADER
        // =============================
        document
          .createElement("div")
          .setAttributes({
            class: "post-header"
          })
          .setChildren(
            document
              .createElement("strong")
              .setText(
                `Post #${id}`
              ),
            document
              .createElement("div")
              .setAttributes({
                class: "post-id"
              })
              .setText(
                `Edits: ${state.edits}`
              )
          ),

        // =============================
        // TEXT
        // =============================
        document
          .createElement("div")
          .setAttributes({
            class: "post-text"
          })
          .setText(
            state.text
          ),

        // =============================
        // ACTIONS
        // =============================
        document
          .createElement("div")
          .setAttributes({
            class: "post-actions"
          })
          .setChildren(
            // ===========================
            // EDIT
            // ===========================
            document
              .createElement("button")
              .setText(
                "Edit"
              )
              .setEvents({
                click() {
                  const next =
                    prompt(
                      "Edit post",
                      state.text
                    );
                  if (
                    next === null
                  ) {
                    return;
                  }
                  setState({
                    text: next,
                    edits:
                      state.edits + 1
                  });
                }
              }),

            // ===========================
            // DELETE
            // ===========================
            document
              .createElement("button")
              .setAttributes({
                class: "secondary"
              })
              .setText(
                "Delete"
              )
              .setEvents({
                click() {
                  posts = posts.filter(
                    (p) => p !== post
                  );
                  renderFeed();
                }
              })
          )
      ]);

  return post;
}

// =====================================
// INPUT
// =====================================
const textarea =
  document
    .createElement("textarea")
    .setAttributes({
      placeholder:
        "Write something..."
    });

// =====================================
// CREATE CONTROLS
// =====================================
const controls =
  document
    .createElement("div")
    .setAttributes({
      class: "row"
    })
    .setChildren(
      // ===============================
      // PREPEND
      // ===============================
      document
        .createElement("button")
        .setText(
          "Prepend Post"
        )
        .setEvents({
          click() {
            const text =
              textarea.value.trim();

            if (!text) {
              return;
            }

            const post =
              createPost(text);

            posts.unshift(post);
            renderFeed();

            textarea.value = "";
          }
        }),

      // ===============================
      // APPEND
      // ===============================
      document
        .createElement("button")
        .setText(
          "Append Post"
        )
        .setEvents({
          click() {
            const text =
              textarea.value.trim();

            if (!text) {
              return;
            }

            const post =
              createPost(text);

            posts.push(post);
            renderFeed();

            textarea.value = "";
          }
        })
    );

// =====================================
// APP
// =====================================
app.setChildren(
  textarea,
  controls,
  feed
);

Live Preview