Guidelines for standardizing CRUD operations (List, Add, Edit, Delete) and Form designs in the UI layer.
This guide outlines the standard architecture and styling for implementing List, Create, Update, and Delete operations, alongside form designs, in the UI layer of any feature.
The List View acts as the entry point for viewing feature records.
PageLayout from @/components/layouts/page-layout as the root container.useQuery paired with the orpc client (e.g., orpc.feature.getAll.queryOptions({ input: { page: 1, limit: 10 } })).actions prop of PageLayout. The button should use BaseButton, include a lucide-react Plus icon, and navigate via @tanstack/react-router Link.[Feature]ListTabledataisLoadingAdd and Edit operations usually share the same underlying Form component but are kept as separate views for clarity.
AdminAdd[Feature]View.tsx / Add[Feature]Modal.tsx)@components/ui/dialog or PageLayout.@base-ui, components like DialogTrigger use the render={<YourElement />} prop instead of Radix's asChild. Example: <DialogTrigger render={<BaseButton>Add</BaseButton>} />isLoading={isPending}).AdminEdit[Feature]View.tsx)id as a prop (from the route).orpc.feature.getById using useQuery to fetch the entity.defaultValues.use[Feature]Form.tsx)This encapsulates the complex logic of data mutations and cache invalidation.
useOrpcMutation from @/hooks/useOrpcMutation.onMutate, cancel outgoing queries, snapshot the previous data, and update the cache so the UI reacts instantly.onSuccess or onSettled, forcefully invalidate the getAll and getById query keys to ensure fresh data.defaultValues object mapping database properties to form expectations.useNavigate from @tanstack/react-router to redirect back to the List view on successful mutation.useBaseForm hook to initialize the react-hook-form context.[Feature]Form.tsx)The standard approach to constructing visually cohesive forms.
<BaseForm> and attach the form and onSubmit props. Include a fade-in animation (animate-in fade-in slide-in-from-bottom-4 duration-500 px-1 pb-4).grid grid-cols-1 md:grid-cols-3 gap-6).
md:col-span-2): For primary inputs like Name, Description, Pricing.<BaseForm.Card title="Section Name"> to create semantic groups of fields (e.g., Basic Information, Pricing, Inventory).<BaseForm.Item control={form.control} name="fieldName" label="Field Label">.<BaseInput>, <BaseSelect>, or shadcn components like <Textarea>.