Getting started with Drayman
Drayman 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:
npx @drayman/framework-init@latest my-appcd my-appnpm startThe website will be available at http://localhost:3033.
Initial component template#
Go to src/components/home.tsx and replace its contents with this code:
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:
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. 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:
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 forceUpdate.
Import it and add to the onchange event after the selected file was saved:
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:

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 to deep-dive into Drayman framework!