Properties
Property Schema
Define your data schema with property types that power filtering, sorting, grouping, and display across all views.
A property schema defines how each field is displayed, filtered, sorted, grouped, and searched.
Full Example
This example shows all 13 property types in a real-world product schema:
import { FilesMediaProperty } from "@sparkyidea/dataview/properties";
import type { DataViewProperty } from "@sparkyidea/dataview/types";
import type { AppRouter } from "@sparkyidea/trpc/routers/index";
import type { inferRouterOutputs } from "@trpc/server";
import { AlertCircle, CheckCircle2, Edit, Eye, XCircle } from "lucide-react";
import { toast } from "sonner";
type RouterOutput = inferRouterOutputs<AppRouter>;
type ProductWithVariants = RouterOutput["product"]["getMany"]["items"][number];
export type Product = ProductWithVariants;
export const productProperties = [
{
key: "productName",
name: "Text",
type: "text",
},
{
key: "price",
name: "Number",
type: "number",
config: {
numberFormat: "dollar",
decimalPlaces: 2,
},
},
{
key: "stockLevel",
name: "Number (Bar)",
type: "number",
config: {
showAs: {
type: "bar",
color: "red",
divideBy: 100,
},
},
},
{
key: "rating",
name: "Number (Ring)",
type: "number",
config: {
showAs: {
type: "ring",
color: "green",
divideBy: 100,
},
},
},
{
key: "category",
name: "Select",
type: "select",
config: {
options: [
{ value: "Accessories", color: "blue" },
{ value: "Bottoms", color: "purple" },
{ value: "Dresses", color: "pink" },
{ value: "Footwear", color: "yellow" },
{ value: "Garden", color: "green" },
{ value: "Home", color: "teal" },
{ value: "Jewelry", color: "gray" },
{ value: "Lingerie", color: "red" },
{ value: "Outerwear", color: "gray" },
{ value: "Tops", color: "blue" },
],
},
},
{
key: "tags",
name: "Multi Select",
type: "multiSelect",
config: {
options: [
{ value: "Bestseller", color: "yellow" },
{ value: "Eco-friendly", color: "green" },
{ value: "Limited Edition", color: "purple" },
{ value: "New Arrival", color: "blue" },
{ value: "On Sale", color: "red" },
{ value: "Seasonal", color: "pink" },
],
},
},
{
key: "availability",
name: "Status",
type: "status",
config: {
groups: [
{
name: "Available",
color: "green",
options: ["In stock"],
icon: CheckCircle2,
},
{
name: "Warning",
color: "yellow",
options: ["Low stock"],
icon: AlertCircle,
},
{
name: "Unavailable",
color: "red",
options: ["Out of stock"],
icon: XCircle,
},
],
},
},
{
key: "lastRestocked",
name: "Date",
type: "date",
},
{
key: "featured",
name: "Checkbox",
type: "checkbox",
},
{
key: "productImage",
name: "Files & Media",
type: "filesMedia",
},
{
key: "productLink",
name: "URL",
type: "url",
enableGroup: false,
},
{
key: "supplierPhone",
name: "Phone",
type: "phone",
},
{
key: "supplierEmail",
name: "Email",
type: "email",
},
{
id: "_totalWorth",
name: "Formula",
type: "formula",
value: (property, item) => (
<div className="flex items-center gap-4">
<FilesMediaProperty className="h-10 w-10" value={item.productImage} />
<div className="flex flex-col items-start justify-center gap-2">
{property("productName")}
<div className="flex items-center gap-2">
{property("price")}
{property("category")}
{property("availability")}
</div>
</div>
</div>
),
},
{
id: "actions",
name: "Actions",
type: "button",
value: (item) => [
{
label: "View",
icon: Eye,
onClick: () => toast.info(`Viewing: ${item.productName}`),
},
{
label: "Edit",
icon: Edit,
onClick: () => toast.info(`Editing: ${item.productName}`),
},
],
},
] as DataViewProperty<Product>[];
Property Types
| Type | Description | Config Required |
|---|---|---|
text | Plain text | ❌ No |
number | Numeric with formatting | Optional |
select | Single selection badge | Optional |
multiSelect | Multiple selection badges | Optional |
status | Grouped status with icons | Optional |
date | Date/time values | Optional |
checkbox | Boolean | ❌ No |
url | Clickable links | Optional |
email | Email addresses | ❌ No |
phone | Phone numbers | ❌ No |
filesMedia | Images and files | ❌ No |
formula | Computed JSX | value() required |
button | Row action buttons | value() required |
Base Property Fields
{
id: string; // Property identifier
type: PropertyType; // One of 13 types
label?: string; // Display label
hidden?: boolean; // Hide in view columns/cards
enableFilter?: boolean; // In filter picker (default: true)
enableSort?: boolean; // In sort picker (default: true)
enableGroup?: boolean; // In group picker (default: true)
enableSearch?: boolean; // In search (default: type-dependent)
}Number Config
{
id: "price",
type: "number",
config: {
numberFormat: "dollar", // number | numberWithCommas | percentage | dollar | euro | pound
decimalPlaces: 2,
showAs: {
type: "bar", // number | bar | ring
color: "green",
divideBy: 100,
showNumber: true,
},
},
}Select / MultiSelect Config
{
id: "category",
type: "select", // or "multiSelect"
config: {
optionOrder: "manual", // manual | asc | desc
options: [
{ value: "Electronics", color: "blue" },
{ value: "Clothing", color: "purple" },
],
},
}Status Config
{
id: "availability",
type: "status",
config: {
groups: [
{
label: "Available",
color: "green",
icon: CheckCircle,
options: ["In stock", "Ready"],
},
{
label: "Warning",
color: "yellow",
icon: AlertCircle,
options: ["Low stock"],
},
],
},
}Date Config
{
id: "createdAt",
type: "date",
config: {
dateFormat: "relative", // full | short | MDY | DMY | YMD | relative | relativeGroup
timeFormat: "12hour", // hidden | 12hour | 24hour
},
}Formula Property
Use formula to compose JSX from existing properties.
{
id: "productCard",
type: "formula",
sortBy: "productName",
value: (property, item) => (
<div className="flex items-center gap-4">
<FilesMediaProperty value={item.productImage} />
<div className="flex flex-col gap-1">
{property("productName")}
<div className="flex gap-2">
{property("price")}
{property("category")}
</div>
</div>
</div>
),
}Button Property
{
id: "actions",
type: "button",
value: (item) => [
{
label: "View",
icon: Eye,
onClick: () => openModal(item.id),
},
{
label: "Edit",
icon: Edit,
onClick: () => router.push(`/edit/${item.id}`),
disabled: !item.canEdit,
},
],
}Type Safety Notes
import type { DataViewProperty } from "@sparkyidea/dataview/types";
interface Product {
id: string;
productName: string;
price: number;
}
const properties = [
{ id: "productName", type: "text" },
{ id: "price", type: "number", config: { numberFormat: "dollar" } },
] satisfies DataViewProperty<Product>[];DataViewProperty<T> validates property shape and type-specific config. Property id is currently a runtime string (not keyof T), so unknown IDs are not compile-time errors.