Deco
Guides

Building Views

Learn how to build custom React frontends in deco

If you want to provide a custom user interface for your agents (for example, a web dashboard or chat UI), deco’s project structure supports a full React + Tailwind frontend that lives alongside the backend. Here’s how the view layer works:

Frontend Stack

Deco’s view is built with React (a popular UI library) and Tailwind CSS (a utility-first CSS framework for styling). The template uses Vite for bundling, and TanStack Router for routing (instead of React Router).

Setting up the View

If you used a template with a view, the basics should already be configured:

  • The CSS is managed by Tailwind (check tailwind.config.js if present, and global styles might be applied via an index CSS or within components).

  • Routing: The template likely has a routes/index.tsx for the home route, and additional route files. New pages can be created by adding new files in src/routes and wiring them into the router in main.tsx (as shown in the template example).

  • State management: Not specifically included by deco by default, but since this is a React app, you can use React context or libraries like Zustand, etc., if needed. For simple apps, you might not need any global state beyond what React Query or the RPC calls provide.

RPC Calls from View to Server

The src/lib/rpc.ts file provides a client that is your gateway to call backend functions from the frontend. This is set up via the @deco/workers-runtime/client library and uses the types from your deco.gen.ts . In practice:

  • To call a Tool from the UI, you do: await client.TOOL_ID(input) .
  • To call a Workflow, do: await client.WORKFLOW_ID(input) .

The client will make an HTTP request to your Worker’s MCP endpoint under the hood, and return the JSON result as a promise. This is super convenient – no need to manually write fetch logic or API endpoints for your own tools. Just ensure your dev server is running (so the calls go through locally), or if deployed, the same client code will call the production endpoint.

For example, imagine you have a tool HELLO_TOOL as earlier. In a React component you might have:

 import { client } from "../lib/rpc";

function GreetingButton() {
  const [message, setMessage] = useState("");
  const sayHello = async () => {
    const result = await client.HELLO_TOOL({ name: "Deco" });
    setMessage(result.greeting);
  };
  return (
    <div>
      <button onClick={sayHello}>Say Hello</button>
      {message && <p>{message}</p>}
    </div>
  );
} 

Clicking the button will invoke the Cloudflare Worker’s HELLO_TOOL and display the greeting. The RPC client handles routing the call to the correct endpoint.

Routing and Navigation

The template uses TanStack Router, which is a type-safe router similar in spirit to React Router. Routes are defined as functions that create route objects. For instance, a MyPage.tsx might export export default (parentRoute) => createRoute({...}) which is then imported in main.tsx and added to the route tree. You can organize nested routes, layouts, and so on. The exact details aren’t crucial for getting started – just know that to add a new page, you likely:

  1. Create a new file in routes/ directory, define the component and route.
  2. Import and include that route in the route tree in main.tsx .
  3. Add a navigation link or programmatic navigation as needed.

UI Components

Tailwind makes styling easier by using classes directly in JSX. You might have pre-made components (buttons, forms, etc.) in src/components . Feel free to build your own or integrate a design system. The key is that the frontend can be any React app; deco doesn’t impose much beyond the RPC setup. So you can use React libraries (charts, modals, etc.) as you normally would.

Connecting to Tools/Workflows

We covered RPC usage. It’s worth noting that because the RPC client is generated from your types, if you add a new tool and re-run npm run gen , your client will automatically have the new method. This prevents calling something that doesn’t exist. If you try to call a tool that you didn’t list in withRuntime on the server, the TypeScript compiler will complain (and at runtime it would 404). So always update the generation after adding new capabilities, and update your UI accordingly.

Hot Reload & Development

During npm run dev , if you edit a React component, HMR (Hot Module Reloading) will update it in the browser without a full refresh. If you edit server code (a tool/workflow), the Worker will restart (the CLI/dev script handles this) and you may need to refresh the page or re-run the action. Check the terminal for any errors on the server side when developing.

In summary, building the view is just like building any React web app, but with the advantage that your backend is just a function call away via the client. This means you don’t have to set up separate REST or GraphQL endpoints for your AI logic – it’s all unified.

(If you prefer not to have a custom view, you can ignore/remove the /view folder. Agents can also be used purely via API or the deco web interface. But for custom applications, the view is where you create tailored experiences for end-users.)

Found an error or want to improve this page?

Edit this page