This guide walks you through two core patterns: building a form with the <One /> component and rendering a data grid with <ListTyped />. Both follow the same schema-first approach — you define the structure as a TypeScript array, and react-declarative handles the rest.
Start by describing the shape of your data as a TypeScript interface. react-declarative uses this to type-check your field schema and give you IntelliSense on name values.
interface IUserProfile {
firstName: string;
lastName: string;
role: string;
birthDate: string;
active: boolean;
}
Create a TypedField<IUserProfile>[] array. Each object in the array describes one field. The name property maps directly to a key on your data type, and the type property controls which input component renders.
import { TypedField, FieldType } from 'react-declarative';
const fields: TypedField<IUserProfile>[] = [
{
type: FieldType.Line,
title: 'Personal details',
},
{
type: FieldType.Group,
desktopColumns: '6',
tabletColumns: '12',
phoneColumns: '12',
fields: [
{
type: FieldType.Text,
name: 'firstName',
title: 'First name',
description: 'Enter your given name',
},
{
type: FieldType.Text,
name: 'lastName',
title: 'Last name',
description: 'Enter your family name',
},
],
},
{
type: FieldType.Combo,
name: 'role',
title: 'Role',
description: 'Select a user role',
itemList: ['admin', 'editor', 'viewer'],
},
{
type: FieldType.Date,
name: 'birthDate',
title: 'Date of birth',
},
{
type: FieldType.Switch,
name: 'active',
title: 'Account active',
},
];
Tip:
FieldType.Groupis a layout container, not a data field. It has noname— it only controls column widths at different breakpoints. Fields nested inside it inherit the responsive grid settings.
Pass your schema to <One /> along with a handler to supply initial data and an onChange callback to receive updates.
import React from 'react';
import { One, TypedField, FieldType } from 'react-declarative';
// ...fields array from Step 2...
const initialData: IUserProfile = {
firstName: 'Jane',
lastName: 'Smith',
role: 'editor',
birthDate: '1990-06-15',
active: true,
};
export function UserProfileForm() {
const handleChange = (data: IUserProfile) => {
console.log('Form data:', data);
// data.firstName, data.role, etc. match the `name` props in your schema
};
return (
<One<IUserProfile>
fields={fields}
handler={() => initialData}
onChange={handleChange}
/>
);
}
The handler prop accepts a plain object, an async function, or a promise. When the form loads, react-declarative calls handler and populates each field from the returned object — matching keys to name values in your schema.
Note: The
onChangecallback fires with the full data object every time any field changes. The keys of that object are exactly thenamestrings you set in your schema.
For tabular data, use <ListTyped />. Define columns and a handler that returns rows and a total count.
import React from 'react';
import {
ListTyped,
TypedField,
FieldType,
IColumn,
ColumnType,
useArrayPaginator,
} from 'react-declarative';
interface IUser {
id: string;
firstName: string;
lastName: string;
role: string;
}
const rows: IUser[] = [
{ id: '1', firstName: 'Jane', lastName: 'Smith', role: 'editor' },
{ id: '2', firstName: 'John', lastName: 'Doe', role: 'admin' },
{ id: '3', firstName: 'Alice', lastName: 'Lee', role: 'viewer' },
];
const filters: TypedField[] = [
{
type: FieldType.Text,
name: 'firstName',
title: 'First name',
},
];
const columns: IColumn<IUser>[] = [
{
type: ColumnType.Text,
field: 'firstName',
headerName: 'First name',
width: () => '200px',
sortable: true,
},
{
type: ColumnType.Text,
field: 'lastName',
headerName: 'Last name',
width: () => '200px',
sortable: true,
},
{
type: ColumnType.Text,
field: 'role',
headerName: 'Role',
width: () => '150px',
},
];
export function UserGrid() {
const handler = useArrayPaginator(rows);
return (
<ListTyped<IUser>
withSearch
withArrowPagination
filters={filters}
columns={columns}
handler={handler}
/>
);
}
useArrayPaginator wraps a static array into the paginator interface that <ListTyped /> expects. For real APIs, replace it with an async function that receives filter values, pagination, and sort state and returns { rows, total }.
Both <One /> and <ListTyped /> work with plain JavaScript objects. The keys of the object returned by onChange (for <One />) or by your handler (for <ListTyped />) correspond directly to the name props in your schema:
schema field: { type: FieldType.Text, name: 'firstName', ... }
data object: { firstName: 'Jane' }
schema field: { type: FieldType.Combo, name: 'role', ... }
data object: { role: 'editor' }
There is no separate mapping step. No reducers. No form context to configure. The library derives the data shape entirely from your schema.
isInvalid, isDisabled, and isVisible callbacks.