UI components library for Payload CMS providing React components, hooks, forms, and styling for building admin interfaces and extensible UI elements.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Complete form management system with validation, state handling, submission, and field rendering capabilities for building dynamic forms in Payload CMS admin interfaces.
Main form wrapper component that provides form context and handles state management.
interface FormProps {
onSubmit?: (data: Record<string, unknown>, actions: FormActions) => void | Promise<void>;
onChange?: (data: Record<string, unknown>) => void;
initialState?: Record<string, unknown>;
disabled?: boolean;
readOnly?: boolean;
validationOperation?: 'create' | 'update';
className?: string;
children?: React.ReactNode;
method?: 'POST' | 'PATCH';
action?: string;
encType?: string;
}
interface FormActions {
reset: () => void;
submit: () => Promise<void>;
validate: () => boolean;
}
function Form(props: FormProps): JSX.Element;Usage example:
import { Form, TextField, FormSubmit } from '@payloadcms/ui';
function DocumentForm() {
const handleSubmit = async (data, { reset }) => {
try {
await saveDocument(data);
reset();
} catch (error) {
console.error('Save failed:', error);
}
};
return (
<Form onSubmit={handleSubmit}>
<TextField path="title" label="Title" required />
<TextField path="content" label="Content" />
<FormSubmit>Save Document</FormSubmit>
</Form>
);
}Form submission button component.
interface FormSubmitProps {
children?: React.ReactNode;
disabled?: boolean;
processing?: boolean;
type?: 'submit' | 'button';
className?: string;
}
function FormSubmit(props: FormSubmitProps): JSX.Element;Dynamically render form fields from configuration.
interface RenderFieldsProps {
fields: FieldConfig[];
path?: string;
margins?: boolean;
className?: string;
readOnly?: boolean;
permissions?: Record<string, unknown>;
}
function RenderFields(props: RenderFieldsProps): JSX.Element;Usage example:
import { RenderFields } from '@payloadcms/ui';
function DynamicForm({ fieldConfig }) {
return (
<Form>
<RenderFields
fields={fieldConfig}
margins={true}
/>
</Form>
);
}Label component for repeatable row fields.
interface RowLabelProps {
data: Record<string, unknown>;
index: number;
path: string;
label?: string;
fallback?: string;
}
function RowLabel(props: RowLabelProps): JSX.Element;Core field state reducer for managing field values and validation.
interface FieldAction {
type: 'UPDATE' | 'VALIDATE' | 'RESET' | 'REMOVE' | 'REPLACE_STATE';
path: string;
value?: unknown;
validate?: boolean;
errorMessage?: string;
disableFormData?: boolean;
}
function fieldReducer(
state: FormState,
action: FieldAction
): FormState;
interface FormState {
[path: string]: FieldState;
}
interface FieldState {
value: unknown;
valid: boolean;
errorMessage?: string;
initialValue?: unknown;
disableFormData?: boolean;
}Access form state and actions through context hooks.
function useFormFields<T>(
selector: (fields: FormFieldsContextType) => T
): T;
function useAllFormFields(): FormFieldsContextType;
function useFormSubmitted(): boolean;
function useFormProcessing(): boolean;
function useFormBackgroundProcessing(): boolean;
function useFormModified(): boolean;
function useFormInitializing(): boolean;Monitor form state changes.
function useWatchForm<T>(): {
getDataByPath: (path: string) => unknown;
getData: () => Record<string, unknown>;
getSiblingData: (path: string) => Record<string, unknown>;
dispatchFields: (action: FieldAction) => void;
};Higher-order component for conditional field rendering.
function withCondition<T extends Record<string, unknown>>(
Component: React.ComponentType<T>
): React.ComponentType<T & ConditionalProps>;
interface ConditionalProps {
admin?: {
condition?: (data: Record<string, unknown>, siblingData?: Record<string, unknown>) => boolean;
};
}Component for watching conditional field logic.
interface WatchConditionProps {
path?: string;
condition: (data: Record<string, unknown>, siblingData?: Record<string, unknown>) => boolean;
children: React.ReactNode;
}
function WatchCondition(props: WatchConditionProps): JSX.Element | null;Component for watching and handling child field errors.
interface WatchChildErrorsProps {
path: string;
children?: React.ReactNode;
}
function WatchChildErrors(props: WatchChildErrorsProps): JSX.Element;Field component for nullifying locale-specific data.
interface NullifyLocaleFieldProps {
path: string;
locale?: string;
}
function NullifyLocaleField(props: NullifyLocaleFieldProps): JSX.Element;Context provider for row label data.
interface RowLabelProviderProps {
children: React.ReactNode;
data: Record<string, unknown>;
index?: number;
path: string;
}
function RowLabelProvider(props: RowLabelProviderProps): JSX.Element;Hook to access row label context data.
function useRowLabel(): {
data: Record<string, unknown>;
index?: number;
path: string;
};import { Form, useForm, SetStepNav } from '@payloadcms/ui';
function MultiStepForm() {
const { getData, validate } = useForm();
const [currentStep, setCurrentStep] = useState(0);
const steps = [
{ label: 'Basic Info', fields: basicFields },
{ label: 'Details', fields: detailFields },
{ label: 'Review', fields: [] }
];
const handleNext = () => {
if (validate()) {
setCurrentStep(prev => prev + 1);
}
};
return (
<Form>
<SetStepNav steps={steps} currentStep={currentStep} />
<RenderFields fields={steps[currentStep].fields} />
<button onClick={handleNext}>Next</button>
</Form>
);
}import { RenderFields, useFormFields } from '@payloadcms/ui';
function ConditionalFields() {
const formData = useFormFields(fields => fields);
const getFieldsForType = (type: string) => {
switch (type) {
case 'article':
return articleFields;
case 'gallery':
return galleryFields;
default:
return baseFields;
}
};
const currentFields = getFieldsForType(formData.type?.value as string);
return <RenderFields fields={currentFields} />;
}import { useField } from '@payloadcms/ui';
function ValidatedEmailField() {
const { value, setValue, showError, errorMessage } = useField<string>({
path: 'email',
validate: (val) => {
if (!val) return 'Email is required';
if (!/\S+@\S+\.\S+/.test(val)) return 'Invalid email format';
return true;
}
});
return (
<div>
<input
type="email"
value={value || ''}
onChange={(e) => setValue(e.target.value)}
/>
{showError && <span className="error">{errorMessage}</span>}
</div>
);
}interface FormFieldsContextType {
[path: string]: FieldState;
}
interface FieldState {
value: unknown;
valid: boolean;
errorMessage?: string;
initialValue?: unknown;
disableFormData?: boolean;
}
interface FieldConfig {
type: string;
name: string;
label?: string;
required?: boolean;
admin?: {
readOnly?: boolean;
disabled?: boolean;
hidden?: boolean;
condition?: (data: Record<string, unknown>) => boolean;
description?: string;
placeholder?: string;
};
validate?: (value: unknown, options: ValidateOptions) => string | true;
}
interface ValidateOptions {
data: Record<string, unknown>;
siblingData: Record<string, unknown>;
operation: 'create' | 'update';
id?: string | number;
}
interface ConditionalProps {
admin?: {
condition?: (
data: Record<string, unknown>,
siblingData?: Record<string, unknown>
) => boolean;
};
}Install with Tessl CLI
npx tessl i tessl/npm-payloadcms--ui