Getting started with Drayman
Tags: drayman, node, typescript, jsx
Published: 2021-08-17 15:54:56

[Drayman](http://www.drayman.io) is a server-side component framework that allows you to use any available HTML element, web component or custom Drayman third-party component together with server-side code in a single script.

With Drayman, the browser only renders what the user should see - all logic and calculations happen server-side and UI is written using JSX syntax.

The best way to show Drayman capabilities is to create something with it. So let's get started.

## File viewer component

Let's build a component that allows the user to select a file from the file system and view it's contents.

First, you need to install Drayman. It can be done by running these commands:

```bash
npx @drayman/framework-init@latest my-app
cd my-app
npm start
```

The website will be available at http://localhost:3033.

If you don't want install anything, you can always try Drayman inside CodeSandbox by visiting [new.drayman.io](http://new.drayman.io).

### Initial component template

Go to `src/components/home.tsx` and replace its contents with this code:

```tsx
export const component: DraymanComponent = async () => {
  return async () => {
    return (
      <>
        <p>Select a file to view it directly from file system</p>
        <select></select>
        <br />
        <pre></pre>
      </>
    );
  };
};
```

You will see an initial skeleton of our component. Further `<select>` will be used to show available files and `<pre>` will show contents of the selected file.

### Filling select with options

Because Drayman runs a component server-side, we can use any Node.js library. In our case we will use the `fs` module.

Let's read file names from the project root directory and fill `<select>` options with them:

```tsx
import { promises as fs } from "fs";

export const component: DraymanComponent = async () => {
  const files = (await fs.readdir("./")).filter((x) => x.includes("."));

  return async () => {
    return (
      <>
        <p>Select a file to view it directly from file system</p>
        <select>
          {files.map((fileName) => (
            <option>{fileName}</option>
          ))}
        </select>
        <br />
        <pre></pre>
      </>
    );
  };
};
```

Right now our component is only showing some elements without any interactivity. Our next step will be to add it.

### Reacting to user actions

We need to remember which file the user has selected to show its contents. It can be done by using the `onchange` event attribute and attaching a function that will be [executed server-side](http://www.drayman.io/docs/components-in-depth/handling-events). We also need to add the `value` attribute to each `option` so that `select` would know which option was selected.

Let's also add the `fs.readFile` function inside the `<pre>` tag so that Drayman would read file contents during re-render. We won't show the `pre` until a file is actually selected:

```tsx
import { promises as fs } from "fs";

export const component: DraymanComponent = async () => {
  const files = (await fs.readdir("./")).filter((x) => x.includes("."));
  let selectedFile;

  return async () => {
    return (
      <>
        <p>Select a file to view it directly from file system</p>
        <select
          onchange={async ({ value }) => {
            selectedFile = value;
          }}
        >
          {files.map((fileName) => (
            <option value={fileName}>{fileName}</option>
          ))}
        </select>
        <br />
        {selectedFile && <pre>{await fs.readFile(selectedFile, "utf-8")}</pre>}
      </>
    );
  };
};
```

If you make a selection from the dropdown, you will see that nothing happens on the page - file contents don't appear. That is because with Drayman you must strictly tell when a component needs to be re-rendered. It can be done by using a special [helper function](http://www.drayman.io/docs/components-in-depth/helpers/introduction) `forceUpdate`.

Import it and add to the `onchange` event after the selected file was saved:

```tsx
import { promises as fs } from "fs";

export const component: DraymanComponent = async ({ forceUpdate, }) => {
  const files = (await fs.readdir("./")).filter((x) => x.includes("."));
  let selectedFile;

  return async () => {
    return (
      <>
        <p>Select a file to view it directly from file system</p>
        <select
          onchange={async ({ value }) => {
            selectedFile = value;
            await forceUpdate();
          }}
        >
          {files.map((fileName) => (
            <option value={fileName}>{fileName}</option>
          ))}
        </select>
        <br />
        {selectedFile && <pre>{await fs.readFile(selectedFile, "utf-8")}</pre>}
      </>
    );
  };
};
```

Now our component is complete and file contents are shown on select:
![blog-getting-started-final-result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b0ed55qu01a43ofyx938.gif)

## Conclusion

We have built a component that combines server-side logic and client-side view in a single script.

If this felt interesting to you, visit the [official docs](http://www.drayman.io/) to deep-dive into Drayman framework!