defineResource
Creates a nested resource (page) within a module. Resources represent individual pages in your application hierarchy.
Signature
typescript
function defineResource(props: DefineResourceProps): Resource;Parameters
path
- Type:
string - Required: Yes
- Description: URL path segment for the resource. Supports dynamic parameters with
:paramsyntax.
typescript
defineResource({
path: ":id", // Dynamic: /products/:id
path: "categories", // Static: /products/categories
});component
- Type:
(props: ResourceComponentProps) => React.ReactNode - Required: Yes
- Description: Page component to render
ResourceComponentProps:
typescript
{
title: string; // Resolved title
icon?: React.ReactNode; // Inherited from module
resources?: Resource[]; // Child resources
}meta
- Type:
object - Required: No
- Description: Metadata configuration
meta.title
- Type:
string | LocalizedString - Default: Capitalized
path - Description: Display title in navigation and breadcrumbs
meta.icon
- Type:
React.ReactNode - Description: Icon override (inherits from module by default)
meta.breadcrumbTitle
- Type:
string | ((segment: string) => string) - Description: Custom breadcrumb segment title
subResources
- Type:
Resource[] - Required: No
- Description: Nested resources within this resource
guards
- Type:
Guard[] - Required: No
- Description: Access control guards
See Guards Overview for details.
errorBoundary
- Type:
React.ReactNode - Required: No
- Description: Error boundary component for this resource
loader
- Type:
(args: LoaderFunctionArgs) => Promise<unknown> | unknown - Required: No
- Description: React Router loader function
Return Type
typescript
Resource;A resource object used in the resources array of defineModule.
Examples
Basic Resource
typescript
import { defineResource } from "@tailor-platform/app-shell";
const detailResource = defineResource({
path: ":id",
component: () => <div>Detail Page</div>,
});Resource with Title
typescript
const categoriesResource = defineResource({
path: "categories",
meta: {
title: "Product Categories",
},
component: CategoriesPage,
});Dynamic Route with useParams
typescript
import { useParams } from "@tailor-platform/app-shell";
const productDetailResource = defineResource({
path: ":id",
meta: {
title: "Product Details",
},
component: () => {
const { id } = useParams();
return <div>Product {id}</div>;
},
});Nested Resources
typescript
const ordersResource = defineResource({
path: "orders",
component: OrdersListPage,
subResources: [
defineResource({
path: ":id",
component: OrderDetailPage,
subResources: [
defineResource({
path: "edit",
component: OrderEditPage,
}),
],
}),
],
});
// URLs:
// /orders
// /orders/:id
// /orders/:id/editResource with Guards
typescript
import { pass, hidden } from "@tailor-platform/app-shell";
const adminSettingsResource = defineResource({
path: "admin-settings",
component: AdminSettingsPage,
guards: [
({ context }) => {
return context.currentUser?.role === "admin" ? pass() : hidden();
},
],
});Resource with Loader
typescript
const productResource = defineResource({
path: ":id",
component: ProductPage,
loader: async ({ params }) => {
const product = await fetch(`/api/products/${params.id}`);
return product.json();
},
});Resource with Error Boundary
typescript
import { useRouteError } from "@tailor-platform/app-shell";
const ErrorBoundary = () => {
const error = useRouteError() as Error;
return <div>Error: {error.message}</div>;
};
const detailResource = defineResource({
path: ":id",
component: DetailPage,
errorBoundary: <ErrorBoundary />,
});Resource with Custom Breadcrumb
typescript
const orderResource = defineResource({
path: ":id",
meta: {
breadcrumbTitle: (segment) => `Order #${segment}`,
},
component: OrderDetailPage,
});
// Breadcrumb shows: "Orders > Order #12345"
// Instead of: "Orders > 12345"Multiple Resources
typescript
const productsModule = defineModule({
path: "products",
component: ProductsPage,
resources: [
defineResource({
path: ":id",
meta: { title: "Product Details" },
component: ProductDetailPage,
}),
defineResource({
path: "categories",
meta: { title: "Categories" },
component: CategoriesPage,
}),
defineResource({
path: "brands",
meta: { title: "Brands" },
component: BrandsPage,
}),
],
});Navigation Behavior
Resources appear in:
- ✅ Sidebar navigation (top-level resources only)
- ✅ Breadcrumbs (all levels)
- ✅ CommandPalette search (all levels)
- ❌ Main navigation menu (use modules instead)
Example Navigation
typescript
defineModule({
path: "products",
component: ProductsPage,
resources: [
defineResource({
path: "all",
component: AllProductsPage, // Appears in sidebar
}),
defineResource({
path: ":id",
component: ProductDetailPage,
subResources: [
defineResource({
path: "edit",
component: EditPage, // Only in breadcrumbs, not sidebar
}),
],
}),
],
});Sidebar:
› Products
- All ProductsBreadcrumbs (on edit page):
Products > Product Details > EditTypeScript
typescript
import { type DefineResourceProps, type Resource } from "@tailor-platform/app-shell";
const props: DefineResourceProps = {
path: ":id",
component: DetailPage,
guards: [],
};
const resource: Resource = defineResource(props);Related
- defineModule - Define top-level modules
- Guards Overview - Access control
- useParams - Access route parameters
- Modules & Resources Concept - Detailed guide