Skip to content

A React data view in ten lines

<UdcDataView collection="books" /> asks a UDC server what books is and draws it: search, filter chips and a filter builder, paging, inline edits, the schema editor, and one tab per renderer the collection’s view.yaml lists. The server here is the one from A server in ten lines, running on port 5100.

  1. A Vite app with React and TypeScript, and the packages:

    Terminal window
    npm create vite@latest books-ui -- --template react-ts && cd books-ui
    npm install @jsudc/react @jsudc/core @tanstack/react-query radix-ui lucide-react
    # the peers of every renderer, for @jsudc/react/all:
    npm install @tanstack/react-table leaflet recharts @dnd-kit/core @dnd-kit/sortable @dnd-kit/utilities
  2. Replace src/main.tsx:

    src/main.tsx
    import "@jsudc/react/styles.css";
    import { UdcClient } from "@jsudc/core/client";
    import { createUdcQueryClient, UdcDataView, UdcI18nProvider, UdcProvider } from "@jsudc/react";
    import { RENDERERS } from "@jsudc/react/all";
    import { Toaster, TooltipProvider } from "@jsudc/react/ui";
    import { QueryClientProvider } from "@tanstack/react-query";
    import { createRoot } from "react-dom/client";
    const client = new UdcClient({ httpUrl: "" }); // same origin: proxy /udc to the server
    createRoot(document.getElementById("root") as HTMLElement).render(
    <UdcProvider client={client} renderers={RENDERERS}>
    <QueryClientProvider client={createUdcQueryClient()}>
    <UdcI18nProvider>
    <TooltipProvider>
    <Toaster>
    <div style={{ display: "flex", flexDirection: "column", height: "100vh" }}>
    <UdcDataView collection="books" />
    </div>
    </Toaster>
    </TooltipProvider>
    </UdcI18nProvider>
    </QueryClientProvider>
    </UdcProvider>,
    );

    UdcClient is the transport from @jsudc/core/client; RENDERERS registers all seven renderers. The providers around the view are the data view’s needs: TanStack Query for the rows, the library’s strings, its tooltips and toasts.

  3. Send /udc to the server:

    vite.config.ts
    import react from "@vitejs/plugin-react";
    import { defineConfig } from "vite";
    export default defineConfig({
    plugins: [react()],
    // the data view POSTs to /udc/<action>; the server of the first quick start answers
    server: { proxy: { "/udc": "http://localhost:5100" } },
    });
    index.html
    <!doctype html>
    <html lang="en">
    <head>
    <meta charset="utf-8" />
    <title>Books</title>
    </head>
    <body>
    <div id="root"></div>
    <script type="module" src="/src/main.tsx"></script>
    </body>
    </html>
  4. npm run dev and open the page: the books as a table, and a Cards tab.

The data view fills its parent as a flex column, so give the parent a height, as the div above does. Show another collection by changing the prop; key the view by collection when one page switches between them.

Each renderer is its own subpath, so a page bundles, and you install the peers of, only the ones you register:

src/renderers.tsx
import { createRendererRegistry } from "@jsudc/react";
import { cardsRenderer } from "@jsudc/react/cards";
import { tableRenderer } from "@jsudc/react/table";
// Only these two are bundled, and only their peers need installing (@tanstack/react-table).
export const renderers = createRendererRegistry(tableRenderer, cardsRenderer);

Pass renderers={renderers} to UdcProvider instead of RENDERERS. A view that lists a renderer you did not register shows the others.

@jsudc/react/styles.css is compiled with every class prefixed, so it cannot collide with your own Tailwind or CSS. Its colours and fonts are CSS variables (--primary, --background, --border, …, with a .dark set): redefine them in your stylesheet, after the library’s, to make the data view yours.