Passing data to components

In Tent, you can pass data to components by using custom data-* attributes. It's simple and easy to understand.

Note: It's by design that JSON.parse() isn't called internally on all data attributes. You should be in full control of the data flow, and you should be explicit about what you expect.

<div data-list='["foo", "bar", "baz"]' data-message="Hello, world!"></div>
import { type Component, mount, tags } from "@tentjs/tent";

const { div, ul, li, p } = tags;

// This type will give your autocompletion in your editor,
// when using `el.dataset.X`. In this case it would suggest `list`, `message` and `amount`.
type Attrs = {
  list: string;
  message: string;
  amount: string;
};

// You could argue that `List` also shouldn't be a component,
// but for the sake of this example, let's keep it as a component.
const List: Component<{}, Attrs> = {
  view: ({ el }) => {
    // Cast the parsed string to an array of strings
    const list: string[] = JSON.parse(el.dataset.list);
    // No need to cast the message, since it's already defined as a string
    const message = el.dataset.message;
    // JSON.parse() will return a number, so no need to cast it
    const amount: number = JSON.parse(el.dataset.amount);

    return div([
      p(`The message is: "${message}"`),
      p(`The amount is: ${amount}`),
      ul(list.map((item, idx) => listItem(item, idx))),
    ]);
  },
};

// This is a pure function - it'll always return the same output for the same input.
// This makes it easy to test and reason about.
const listItem = (item: string, idx: number) => {
  return li(`Item ${idx}: ${item}`);
};

// In a real app, you would probably put `listItem` in a separate file.
export { List, listItem };