diff --git a/package-lock.json b/package-lock.json
index 242a2ff038..2b5e720378 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16,6 +16,7 @@
"packages/mui",
"packages/playground",
"packages/react-bootstrap",
+ "packages/primereact",
"packages/semantic-ui",
"packages/utils",
"packages/validator-ajv8",
@@ -9929,6 +9930,10 @@
"resolved": "packages/playground",
"link": true
},
+ "node_modules/@rjsf/primereact": {
+ "resolved": "packages/primereact",
+ "link": true
+ },
"node_modules/@rjsf/react-bootstrap": {
"resolved": "packages/react-bootstrap",
"link": true
@@ -30700,6 +30705,44 @@
"node": ">=4"
}
},
+ "node_modules/primeflex": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/primeflex/-/primeflex-3.3.1.tgz",
+ "integrity": "sha512-zaOq3YvcOYytbAmKv3zYc+0VNS9Wg5d37dfxZnveKBFPr7vEIwfV5ydrpiouTft8MVW6qNjfkaQphHSnvgQbpQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/primeicons": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/primeicons/-/primeicons-7.0.0.tgz",
+ "integrity": "sha512-jK3Et9UzwzTsd6tzl2RmwrVY/b8raJ3QZLzoDACj+oTJ0oX7L9Hy+XnVwgo4QVKlKpnP/Ur13SXV/pVh4LzaDw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/primereact": {
+ "version": "10.9.5",
+ "resolved": "https://registry.npmjs.org/primereact/-/primereact-10.9.5.tgz",
+ "integrity": "sha512-4O6gm0LrKF7Ml8zQmb8mGiWS/ugJ94KBOAS/CAxWFQh9qyNgfNw/qcpCeomPIkjWd98jrM2XDiEbgq+W0395Hw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/react-transition-group": "^4.4.1",
+ "react-transition-group": "^4.4.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react": "^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/prism-react-renderer": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-2.4.1.tgz",
@@ -38090,6 +38133,7 @@
"@rjsf/core": "^6.0.0-beta.10",
"@rjsf/fluentui-rc": "^6.0.0-beta.10",
"@rjsf/mui": "^6.0.0-beta.10",
+ "@rjsf/primereact": "^6.0.0-beta.10",
"@rjsf/react-bootstrap": "^6.0.0-beta.10",
"@rjsf/semantic-ui": "^6.0.0-beta.10",
"@rjsf/utils": "^6.0.0-beta.10",
@@ -38145,6 +38189,32 @@
"react": "^18.2.0"
}
},
+ "packages/primereact": {
+ "name": "@rjsf/primereact",
+ "version": "6.0.0-beta.10",
+ "license": "Apache-2.0",
+ "devDependencies": {
+ "@rjsf/core": "^6.0.0-beta.10",
+ "@rjsf/snapshot-tests": "^6.0.0-beta.10",
+ "@rjsf/utils": "^6.0.0-beta.10",
+ "@rjsf/validator-ajv8": "^6.0.0-beta.10",
+ "@rollup/plugin-replace": "^6.0.2",
+ "eslint": "^8.56.0",
+ "primeflex": "^3.3.1",
+ "primeicons": "^7.0.0",
+ "primereact": "^10.9.2"
+ },
+ "engines": {
+ "node": ">=20"
+ },
+ "peerDependencies": {
+ "@rjsf/core": "^6.0.0-beta",
+ "@rjsf/utils": "^6.0.0-beta",
+ "primeicons": ">=6.0.0",
+ "primereact": ">=8.0.0",
+ "react": ">=18"
+ }
+ },
"packages/react-bootstrap": {
"name": "@rjsf/react-bootstrap",
"version": "6.0.0-beta.10",
diff --git a/package.json b/package.json
index de85797e0d..a750cf0ee1 100644
--- a/package.json
+++ b/package.json
@@ -95,6 +95,7 @@
"packages/fluentui-rc",
"packages/mui",
"packages/playground",
+ "packages/primereact",
"packages/react-bootstrap",
"packages/semantic-ui",
"packages/utils",
diff --git a/packages/docs/docs/api-reference/themes/primereact/uiSchema.md b/packages/docs/docs/api-reference/themes/primereact/uiSchema.md
new file mode 100644
index 0000000000..ada5378d87
--- /dev/null
+++ b/packages/docs/docs/api-reference/themes/primereact/uiSchema.md
@@ -0,0 +1,38 @@
+# PrimeReact Customization
+
+You may set PrimeReact-specific options in the `uiSchema` object using the `"prime"` `"ui:option"`.
+
+```json
+{
+ "password": {
+ "ui:options": {
+ "prime": {
+ "feedback": true,
+ "weakLabel": "Too weak",
+ "mediumLabel": "Could be stronger",
+ "strongLabel": "Strong password",
+ "toggleMask": true
+ }
+ }
+ }
+}
+```
+
+## Components
+
+The `@rjsf/primereact` theme renders to the following PrimeReact components:
+
+- [`InputText`](https://primereact.org/inputtext/) as the default widget
+- [`AutoComplete`](https://primereact.org/autocomplete/) as the default with `examples`
+- [`Checkbox`](https://primereact.org/checkbox/) for boolean fields and `checkboxes` widget
+- [`ColorPicker`](https://primereact.org/colorpicker/) as `color` widget
+- [`Password`](https://primereact.org/password/) as `password` widget
+- [`RadioButton`](https://primereact.org/radiobutton/) as `radio` widget
+- [`Slider`](https://primereact.org/slider/) as `range` widget
+- [`Dropdown`](https://primereact.org/dropdown/) as `select` widget
+- [`MultiSelect`](https://primereact.org/multiselect/) as `select` widget with `multiple` option
+- [`InputTextarea`](https://primereact.org/inputtextarea/) as `textarea` widget
+- [`InputNumber`](https://primereact.org/inputnumber/) as `updown` widget
+
+Please refer to the [PrimeReact documentation](https://primereact.org/) for the available PrimeReact-specific options
+of each component.
diff --git a/packages/docs/docs/usage/themes.md b/packages/docs/docs/usage/themes.md
index d34942999b..ad9629dfcb 100644
--- a/packages/docs/docs/usage/themes.md
+++ b/packages/docs/docs/usage/themes.md
@@ -8,11 +8,12 @@ meaning that you must load the Bootstrap stylesheet on the page to view the form
| Theme Name | Status | Package Name / Link |
| --------------------- | --------- | ----------------------- |
| antd | Published | `@rjsf/antd` |
-| Bootstrap 3 (default) | Published | `@rjsf/core` |
-| react-bootstrap | Published | `@rjsf/react-bootstrap` |
| Chakra UI | Published | `@rjsf/chakra-ui` |
+| Bootstrap 3 (default) | Published | `@rjsf/core` |
| fluentui-rc | Published | `@rjsf/fluentui-rc` |
| material-ui | Published | `@rjsf/mui` |
+| PrimeReact | - | `@rjsf/primereact` |
+| react-bootstrap | Published | `@rjsf/react-bootstrap` |
| Semantic UI | Published | `@rjsf/semantic-ui` |
| shadcn | Published | `@rjsf/shadcn` |
diff --git a/packages/playground/package.json b/packages/playground/package.json
index 46c80bee39..fbe9afad89 100644
--- a/packages/playground/package.json
+++ b/packages/playground/package.json
@@ -44,6 +44,7 @@
"@rjsf/core": "^6.0.0-beta.10",
"@rjsf/fluentui-rc": "^6.0.0-beta.10",
"@rjsf/mui": "^6.0.0-beta.10",
+ "@rjsf/primereact": "^6.0.0-beta.10",
"@rjsf/react-bootstrap": "^6.0.0-beta.10",
"@rjsf/semantic-ui": "^6.0.0-beta.10",
"@rjsf/utils": "^6.0.0-beta.10",
diff --git a/packages/playground/src/app.tsx b/packages/playground/src/app.tsx
index ac88ccdcaf..1ea90154ff 100644
--- a/packages/playground/src/app.tsx
+++ b/packages/playground/src/app.tsx
@@ -6,6 +6,7 @@ import { Theme as BootstrapTheme } from '@rjsf/react-bootstrap';
import { Theme as ChakraUITheme } from '@rjsf/chakra-ui';
import { Theme as shadcnTheme } from '@rjsf/shadcn';
import { Theme as DaisyUITheme } from '@rjsf/daisyui';
+import { Theme as PrimeReactTheme } from '@rjsf/primereact';
import v8Validator, { customizeValidator } from '@rjsf/validator-ajv8';
import Ajv2019 from 'ajv/dist/2019.js';
import Ajv2020 from 'ajv/dist/2020.js';
@@ -151,6 +152,168 @@ const themes: PlaygroundProps['themes'] = {
stylesheet: '//cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css',
theme: BootstrapTheme,
},
+ primereact: {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/lara-light-cyan/theme.css',
+ theme: PrimeReactTheme,
+ subthemes: {
+ 'arya-blue': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/arya-blue/theme.css',
+ },
+ 'arya-green': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/arya-green/theme.css',
+ },
+ 'arya-orange': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/arya-orange/theme.css',
+ },
+ 'arya-purple': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/arya-purple/theme.css',
+ },
+ 'bootstrap4-dark-blue': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/bootstrap4-dark-blue/theme.css',
+ },
+ 'bootstrap4-dark-purple': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/bootstrap4-dark-purple/theme.css',
+ },
+ 'bootstrap4-light-blue': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/bootstrap4-light-blue/theme.css',
+ },
+ 'bootstrap4-light-purple': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/bootstrap4-light-purple/theme.css',
+ },
+ 'fluent-light': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/fluent-light/theme.css',
+ },
+ 'lara-dark-amber': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/lara-dark-amber/theme.css',
+ },
+ 'lara-dark-blue': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/lara-dark-blue/theme.css',
+ },
+ 'lara-dark-cyan': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/lara-dark-cyan/theme.css',
+ },
+ 'lara-dark-green': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/lara-dark-green/theme.css',
+ },
+ 'lara-dark-indigo': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/lara-dark-indigo/theme.css',
+ },
+ 'lara-dark-pink': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/lara-dark-pink/theme.css',
+ },
+ 'lara-dark-purple': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/lara-dark-purple/theme.css',
+ },
+ 'lara-dark-teal': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/lara-dark-teal/theme.css',
+ },
+ 'lara-light-amber': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/lara-light-amber/theme.css',
+ },
+ 'lara-light-blue': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/lara-light-blue/theme.css',
+ },
+ 'lara-light-cyan': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/lara-light-cyan/theme.css',
+ },
+ 'lara-light-green': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/lara-light-green/theme.css',
+ },
+ 'lara-light-indigo': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/lara-light-indigo/theme.css',
+ },
+ 'lara-light-pink': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/lara-light-pink/theme.css',
+ },
+ 'lara-light-purple': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/lara-light-purple/theme.css',
+ },
+ 'lara-light-teal': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/lara-light-teal/theme.css',
+ },
+ 'luna-amber': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/luna-amber/theme.css',
+ },
+ 'luna-blue': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/luna-blue/theme.css',
+ },
+ 'luna-green': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/luna-green/theme.css',
+ },
+ 'luna-pink': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/luna-pink/theme.css',
+ },
+ 'md-dark-deeppurple': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/md-dark-deeppurple/theme.css',
+ },
+ 'md-dark-indigo': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/md-dark-indigo/theme.css',
+ },
+ 'md-light-deeppurple': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/md-light-deeppurple/theme.css',
+ },
+ 'md-light-indigo': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/md-light-indigo/theme.css',
+ },
+ 'mdc-dark-deeppurple': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/mdc-dark-deeppurple/theme.css',
+ },
+ 'mdc-dark-indigo': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/mdc-dark-indigo/theme.css',
+ },
+ 'mdc-light-deeppurple': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/mdc-light-deeppurple/theme.css',
+ },
+ 'mdc-light-indigo': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/mdc-light-indigo/theme.css',
+ },
+ mira: {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/mira/theme.css',
+ },
+ nano: {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/nano/theme.css',
+ },
+ nova: {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/nova/theme.css',
+ },
+ 'nova-accent': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/nova-accent/theme.css',
+ },
+ 'nova-alt': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/nova-alt/theme.css',
+ },
+ rhea: {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/rhea/theme.css',
+ },
+ 'saga-blue': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/saga-blue/theme.css',
+ },
+ 'saga-green': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/saga-green/theme.css',
+ },
+ 'saga-orange': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/saga-orange/theme.css',
+ },
+ 'saga-purple': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/saga-purple/theme.css',
+ },
+ 'soho-dark': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/soho-dark/theme.css',
+ },
+ 'soho-light': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/soho-light/theme.css',
+ },
+ 'tailwind-light': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/tailwind-light/theme.css',
+ },
+ 'viva-dark': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/viva-dark/theme.css',
+ },
+ 'viva-light': {
+ stylesheet: '//cdn.jsdelivr.net/npm/primereact@10.9.2/resources/themes/viva-light/theme.css',
+ },
+ },
+ },
'semantic-ui': {
stylesheet: '//cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.css',
theme: SuiTheme,
diff --git a/packages/playground/src/components/DemoFrame.tsx b/packages/playground/src/components/DemoFrame.tsx
index 045ae7b627..76faedd8f7 100644
--- a/packages/playground/src/components/DemoFrame.tsx
+++ b/packages/playground/src/components/DemoFrame.tsx
@@ -7,6 +7,7 @@ import { __createChakraFrameProvider } from '@rjsf/chakra-ui';
import { StyleProvider as AntdStyleProvider } from '@ant-design/cssinjs';
import { __createFluentUIRCFrameProvider } from '@rjsf/fluentui-rc';
import { __createDaisyUIFrameProvider } from '@rjsf/daisyui';
+import { PrimeReactProvider } from 'primereact/api';
/*
Adapted from https://github.com/mui-org/material-ui/blob/master/docs/src/modules/components/DemoSandboxed.js
@@ -94,6 +95,14 @@ export default function DemoFrame(props: DemoFrameProps) {
})}
) : null;
+ } else if (theme === 'primereact') {
+ body = ready ? (
+ <>
+
+
+ {children}
+ >
+ ) : null;
}
return (
diff --git a/packages/playground/src/samples/layoutGrid.tsx b/packages/playground/src/samples/layoutGrid.tsx
index 6054f2fafd..511bcf5126 100644
--- a/packages/playground/src/samples/layoutGrid.tsx
+++ b/packages/playground/src/samples/layoutGrid.tsx
@@ -1923,6 +1923,167 @@ const layoutGrid: Sample = {
},
},
};
+ case 'primereact':
+ return {
+ 'ui:field': 'LayoutGridField',
+ 'ui:layoutGrid': {
+ 'ui:row': {
+ children: [
+ {
+ 'ui:col': {
+ children: ['person'],
+ },
+ },
+ {
+ 'ui:columns': {
+ xs: 4,
+ children: ['person.name.first', 'person.name.middle', 'person.name.last'],
+ },
+ },
+ {
+ 'ui:col': {
+ sm: 4,
+ children: ['person.birth_date'],
+ },
+ },
+ {
+ 'ui:col': {
+ sm: 8,
+ children: ['person.race'],
+ },
+ },
+ {
+ 'ui:col': {
+ sm: 6,
+ children: [
+ {
+ 'ui:row': {
+ children: [
+ {
+ 'ui:columns': {
+ children: ['person.address.line_1', 'person.address.line_2', 'person.address.city'],
+ },
+ },
+ {
+ 'ui:columns': {
+ sm: 6,
+ children: ['person.address.state', 'person.address.postal_code'],
+ },
+ },
+ ],
+ },
+ },
+ ],
+ },
+ },
+ {
+ 'ui:col': {
+ sm: 6,
+ children: [
+ {
+ 'ui:row': {
+ children: [
+ {
+ 'ui:columns': {
+ children: ['employment'],
+ },
+ },
+ {
+ 'ui:condition': {
+ field: 'employment.job_type',
+ value: 'company',
+ operator: 'all',
+ children: [
+ {
+ 'ui:columns': {
+ children: ['employment.business', 'employment.title'],
+ },
+ },
+ {
+ 'ui:col': {
+ children: ['employment.location.city'],
+ },
+ },
+ {
+ 'ui:col': {
+ children: ['employment.location.state'],
+ },
+ },
+ ],
+ },
+ },
+ {
+ 'ui:condition': {
+ field: 'employment.job_type',
+ value: 'education',
+ operator: 'all',
+ children: [
+ {
+ 'ui:columns': {
+ children: ['employment.district', 'employment.school', 'employment.title'],
+ },
+ },
+ {
+ 'ui:col': {
+ children: ['employment.location.city'],
+ },
+ },
+ {
+ 'ui:col': {
+ children: ['employment.location.state'],
+ },
+ },
+ ],
+ },
+ },
+ {
+ 'ui:condition': {
+ field: 'employment.job_type',
+ value: 'other',
+ operator: 'all',
+ children: [
+ {
+ 'ui:columns': {
+ children: [
+ {
+ name: 'employment.description',
+ rows: 6,
+ },
+ ],
+ },
+ },
+ ],
+ },
+ },
+ ],
+ },
+ },
+ ],
+ },
+ },
+ ],
+ },
+ },
+ person: {
+ 'ui:field': 'LayoutHeaderField',
+ race: {
+ 'ui:options': {
+ widget: 'checkboxes',
+ },
+ },
+ address: {
+ 'ui:field': 'LayoutGridField',
+ },
+ },
+ employment: {
+ 'ui:options': {
+ inline: true,
+ },
+ description: {
+ 'ui:widget': 'textarea',
+ },
+ },
+ };
default:
return {
'ui:field': 'LayoutGridField',
diff --git a/packages/playground/tsconfig.json b/packages/playground/tsconfig.json
index 1d8bcd8d5b..d8894b2927 100644
--- a/packages/playground/tsconfig.json
+++ b/packages/playground/tsconfig.json
@@ -53,6 +53,9 @@
{
"path": "../mui"
},
+ {
+ "path": "../primereact"
+ },
{
"path": "../react-bootstrap"
},
diff --git a/packages/playground/vite.config.ts b/packages/playground/vite.config.ts
index 65821a815c..dc571fee62 100644
--- a/packages/playground/vite.config.ts
+++ b/packages/playground/vite.config.ts
@@ -20,6 +20,7 @@ export default defineConfig({
'@rjsf/core': path.resolve(__dirname, '../core/src'),
'@rjsf/fluentui-rc': path.resolve(__dirname, '../fluentui-rc/src'),
'@rjsf/mui': path.resolve(__dirname, '../mui/src'),
+ '@rjsf/primereact': path.resolve(__dirname, '../primereact/src'),
'@rjsf/react-bootstrap': path.resolve(__dirname, '../react-bootstrap/src'),
'@rjsf/semantic-ui': path.resolve(__dirname, '../semantic-ui/src'),
'@rjsf/shadcn': path.resolve(__dirname, '../shadcn/src'),
diff --git a/packages/primereact/.eslintrc b/packages/primereact/.eslintrc
new file mode 100644
index 0000000000..8f31b04e27
--- /dev/null
+++ b/packages/primereact/.eslintrc
@@ -0,0 +1,9 @@
+{
+ "extends": "../../.eslintrc",
+ "plugins": [
+ "@typescript-eslint",
+ "jsx-a11y",
+ "react",
+ "import"
+ ]
+}
diff --git a/packages/primereact/README.md b/packages/primereact/README.md
new file mode 100644
index 0000000000..c6835c580f
--- /dev/null
+++ b/packages/primereact/README.md
@@ -0,0 +1,120 @@
+[![Build Status][build-shield]][build-url]
+[![npm][npm-shield]][npm-url]
+[![npm downloads][npm-dl-shield]][npm-dl-url]
+[![Contributors][contributors-shield]][contributors-url]
+[![Apache 2.0 License][license-shield]][license-url]
+
+
+
+
+
+
+
+
@rjsf/primereact
+
+
+ PrimeReact theme, fields, and widgets for react-jsonschema-form
.
+
+ Explore the docs »
+
+
+ View Playground
+ ·
+ Report Bug
+ ·
+ Request Feature
+
+
+
+## Table of Contents
+
+- [About The Project](#about-the-project)
+ - [Built With](#built-with)
+- [Getting Started](#getting-started)
+ - [Prerequisites](#prerequisites)
+ - [Installation](#installation)
+- [Usage](#usage)
+- [Roadmap](#roadmap)
+- [Contributing](#contributing)
+- [Contact](#contact)
+
+## About The Project
+
+PrimeReact theme, fields, and widgets for `react-jsonschema-form`.
+
+### Built With
+
+- [react-jsonschema-form](https://github.com/rjsf-team/react-jsonschema-form/)
+- [PrimeReact](https://github.com/primefaces/primereact)
+
+## Getting Started
+
+### Prerequisites
+
+- `primereact >= 8.0.0`
+- `primeicons >= 6.0.0`
+- `@rjsf/core >= 6`
+- `@rjsf/utils >= 6`
+- `@rjsf/validator-ajv8 >= 6`
+
+```sh
+npm install primereact primeicons @rjsf/core
+```
+
+### Installation
+
+```sh
+npm install @rjsf/primereact
+```
+
+## Usage
+
+```javascript
+import Form from '@rjsf/primereact';
+```
+
+or
+
+```javascript
+import { withTheme } from '@rjsf/core';
+import { Theme as PrimeReactTheme } from '@rjsf/primereact';
+
+// Customize the theme with your own fields and widgets
+
+const Form = withTheme(PrimeReactTheme);
+```
+
+## Roadmap
+
+See the general [open issues](https://github.com/rjsf-team/react-jsonschema-form/issues).
+
+## Contributing
+
+Read our [contributors' guide](https://rjsf-team.github.io/react-jsonschema-form/docs/contributing/) to get started.
+
+## Contact
+
+rjsf team: [https://github.com/orgs/rjsf-team/people](https://github.com/orgs/rjsf-team/people)
+
+GitHub
+repository: [https://github.com/rjsf-team/react-jsonschema-form](https://github.com/rjsf-team/react-jsonschema-form)
+
+[build-shield]: https://github.com/rjsf-team/react-jsonschema-form/workflows/CI/badge.svg
+
+[build-url]: https://github.com/rjsf-team/react-jsonschema-form/actions
+
+[contributors-shield]: https://img.shields.io/github/contributors/rjsf-team/react-jsonschema-form.svg
+
+[contributors-url]: https://github.com/rjsf-team/react-jsonschema-form/graphs/contributors
+
+[license-shield]: https://img.shields.io/badge/license-Apache%202.0-blue.svg?style=flat-square
+
+[license-url]: https://choosealicense.com/licenses/apache-2.0/
+
+[npm-shield]: https://img.shields.io/npm/v/@rjsf/primereact/latest.svg?style=flat-square
+
+[npm-url]: https://www.npmjs.com/package/@rjsf/primereact
+
+[npm-dl-shield]: https://img.shields.io/npm/dm/@rjsf/primereact.svg?style=flat-square
+
+[npm-dl-url]: https://www.npmjs.com/package/@rjsf/primereact
diff --git a/packages/primereact/babel.config.json b/packages/primereact/babel.config.json
new file mode 100644
index 0000000000..ac08da0a4a
--- /dev/null
+++ b/packages/primereact/babel.config.json
@@ -0,0 +1,3 @@
+{
+ "extends": "../../babel.config.json"
+}
diff --git a/packages/primereact/jest.config.json b/packages/primereact/jest.config.json
new file mode 100644
index 0000000000..715150b8f4
--- /dev/null
+++ b/packages/primereact/jest.config.json
@@ -0,0 +1,13 @@
+{
+ "testEnvironment": "jsdom",
+ "transform": {
+ "^.+\\.(ts|tsx|js|jsx)$": ["babel-jest", { "configFile": "./babel.config.json" }]
+ },
+ "transformIgnorePatterns": ["/node_modules/(?!nanoid/.*)"],
+ "moduleNameMapper": {
+ "^@/(.*)$": "/src/$1"
+ },
+ "setupFilesAfterEnv": [
+ "/test/setup.ts"
+ ]
+}
diff --git a/packages/primereact/logo.png b/packages/primereact/logo.png
new file mode 100644
index 0000000000..b4a65d42e6
Binary files /dev/null and b/packages/primereact/logo.png differ
diff --git a/packages/primereact/package.json b/packages/primereact/package.json
new file mode 100644
index 0000000000..f4bce48d01
--- /dev/null
+++ b/packages/primereact/package.json
@@ -0,0 +1,104 @@
+{
+ "name": "@rjsf/primereact",
+ "version": "6.0.0-beta.10",
+ "description": "PrimeReact theme, fields and widgets for react-jsonschema-form",
+ "main": "dist/index.js",
+ "module": "lib/index.js",
+ "typings": "lib/index.d.ts",
+ "type": "module",
+ "exports": {
+ ".": {
+ "types": "./lib/index.d.ts",
+ "require": "./dist/index.js",
+ "import": "./lib/index.js"
+ },
+ "./lib": {
+ "types": "./lib/index.d.ts",
+ "require": "./dist/index.js",
+ "import": "./lib/index.js"
+ },
+ "./lib/*.js": {
+ "types": "./lib/*.d.ts",
+ "require": "./dist/*.js",
+ "import": "./lib/*.js"
+ },
+ "./dist": {
+ "types": "./lib/index.d.ts",
+ "require": "./dist/index.js",
+ "import": "./lib/index.js"
+ },
+ "./dist/*.js": {
+ "types": "./lib/*.d.ts",
+ "require": "./dist/*.js",
+ "import": "./lib/*.js"
+ }
+ },
+ "scripts": {
+ "build:ts": "tsc -b tsconfig.build.json && tsc-alias -p tsconfig.build.json",
+ "build:cjs": "esbuild ./src/index.ts --bundle --outfile=dist/index.js --sourcemap --packages=external --format=cjs",
+ "build:esm": "esbuild ./src/index.ts --bundle --outfile=dist/primereact.esm.js --sourcemap --packages=external --format=esm",
+ "build:umd": "rollup dist/primereact.esm.js --format=umd --file=dist/primereact.umd.js --name=@rjsf/primereact",
+ "build": "npm run build:ts && npm run build:cjs && npm run build:esm && npm run build:umd",
+ "cs-check": "prettier -l \"{src,test}/**/*.ts?(x)\"",
+ "cs-format": "prettier \"{src,test}/**/*.ts?(x)\" --write",
+ "lint": "eslint src test",
+ "precommit": "lint-staged",
+ "test": "jest",
+ "test:update": "jest --u"
+ },
+ "lint-staged": {
+ "{src,test}/**/*.ts?(x)": [
+ "eslint --fix"
+ ]
+ },
+ "files": [
+ "dist",
+ "lib",
+ "src"
+ ],
+ "engineStrict": false,
+ "engines": {
+ "node": ">=20"
+ },
+ "peerDependencies": {
+ "@rjsf/core": "^6.0.0-beta",
+ "@rjsf/utils": "^6.0.0-beta",
+ "primeicons": ">=6.0.0",
+ "primereact": ">=8.0.0",
+ "react": ">=18"
+ },
+ "devDependencies": {
+ "@rjsf/core": "^6.0.0-beta.10",
+ "@rjsf/snapshot-tests": "^6.0.0-beta.10",
+ "@rjsf/utils": "^6.0.0-beta.10",
+ "@rjsf/validator-ajv8": "^6.0.0-beta.10",
+ "@rollup/plugin-replace": "^6.0.2",
+ "eslint": "^8.56.0",
+ "primeicons": "^7.0.0",
+ "primeflex": "^3.3.1",
+ "primereact": "^10.9.2"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/rjsf-team/react-jsonschema-form.git"
+ },
+ "keywords": [
+ "primereact",
+ "primeicons",
+ "react",
+ "react-jsonschema-form",
+ "jsonschema",
+ "json-schema",
+ "json",
+ "rjsf-primereact"
+ ],
+ "author": "Arnold Daniels ",
+ "license": "Apache-2.0",
+ "bugs": {
+ "url": "https://github.com/rjsf-team/react-jsonschema-form/issues"
+ },
+ "homepage": "https://github.com/rjsf-team/react-jsonschema-form",
+ "publishConfig": {
+ "access": "public"
+ }
+}
diff --git a/packages/primereact/src/AddButton/AddButton.tsx b/packages/primereact/src/AddButton/AddButton.tsx
new file mode 100644
index 0000000000..86876e7b07
--- /dev/null
+++ b/packages/primereact/src/AddButton/AddButton.tsx
@@ -0,0 +1,23 @@
+import { Button } from 'primereact/button';
+import { FormContextType, IconButtonProps, RJSFSchema, StrictRJSFSchema, TranslatableString } from '@rjsf/utils';
+
+/** The `AddButton` renders a button that represents the `Add` action on a form
+ */
+export default function AddButton({
+ uiSchema,
+ registry,
+ color,
+ ...props
+}: IconButtonProps) {
+ const { translateString } = registry;
+ return (
+
+ );
+}
diff --git a/packages/primereact/src/AddButton/index.ts b/packages/primereact/src/AddButton/index.ts
new file mode 100644
index 0000000000..752d720d32
--- /dev/null
+++ b/packages/primereact/src/AddButton/index.ts
@@ -0,0 +1,2 @@
+export { default } from './AddButton';
+export * from './AddButton';
diff --git a/packages/primereact/src/ArrayFieldItemTemplate/ArrayFieldItemTemplate.tsx b/packages/primereact/src/ArrayFieldItemTemplate/ArrayFieldItemTemplate.tsx
new file mode 100644
index 0000000000..1d1062c527
--- /dev/null
+++ b/packages/primereact/src/ArrayFieldItemTemplate/ArrayFieldItemTemplate.tsx
@@ -0,0 +1,40 @@
+import {
+ ArrayFieldItemTemplateType,
+ FormContextType,
+ getTemplate,
+ getUiOptions,
+ RJSFSchema,
+ StrictRJSFSchema,
+} from '@rjsf/utils';
+
+/** The `ArrayFieldItemTemplate` component is the template used to render an items of an array.
+ *
+ * @param props - The `ArrayFieldItemTemplateType` props for the component
+ */
+export default function ArrayFieldItemTemplate<
+ T = any,
+ S extends StrictRJSFSchema = RJSFSchema,
+ F extends FormContextType = any,
+>(props: ArrayFieldItemTemplateType) {
+ const { children, buttonsProps, hasToolbar, uiSchema, registry } = props;
+ const uiOptions = getUiOptions(uiSchema);
+ const ArrayFieldItemButtonsTemplate = getTemplate<'ArrayFieldItemButtonsTemplate', T, S, F>(
+ 'ArrayFieldItemButtonsTemplate',
+ registry,
+ uiOptions,
+ );
+ return (
+
+ {hasToolbar && (
+
+ {hasToolbar && (
+
+ )}
+
+ )}
+ {children}
+
+ );
+}
diff --git a/packages/primereact/src/ArrayFieldItemTemplate/index.ts b/packages/primereact/src/ArrayFieldItemTemplate/index.ts
new file mode 100644
index 0000000000..f104431399
--- /dev/null
+++ b/packages/primereact/src/ArrayFieldItemTemplate/index.ts
@@ -0,0 +1,2 @@
+export { default } from './ArrayFieldItemTemplate';
+export * from './ArrayFieldItemTemplate';
diff --git a/packages/primereact/src/ArrayFieldTemplate/ArrayFieldTemplate.tsx b/packages/primereact/src/ArrayFieldTemplate/ArrayFieldTemplate.tsx
new file mode 100644
index 0000000000..f2facc74bb
--- /dev/null
+++ b/packages/primereact/src/ArrayFieldTemplate/ArrayFieldTemplate.tsx
@@ -0,0 +1,111 @@
+import {
+ getTemplate,
+ getUiOptions,
+ isFixedItems,
+ ArrayFieldTemplateProps,
+ ArrayFieldItemTemplateType,
+ FormContextType,
+ RJSFSchema,
+ StrictRJSFSchema,
+ UI_OPTIONS_KEY,
+ buttonId,
+} from '@rjsf/utils';
+import { Fieldset } from 'primereact/fieldset';
+import AddButton from '../AddButton';
+
+/** The `ArrayFieldTemplate` component is the template used to render all items in an array.
+ *
+ * @param props - The `ArrayFieldItemTemplateType` props for the component
+ */
+export default function ArrayFieldTemplate<
+ T = any,
+ S extends StrictRJSFSchema = RJSFSchema,
+ F extends FormContextType = any,
+>(props: ArrayFieldTemplateProps) {
+ const {
+ uiSchema,
+ idSchema,
+ canAdd,
+ className,
+ disabled,
+ items,
+ onAddClick,
+ readonly,
+ schema,
+ title,
+ registry,
+ required,
+ ...rest
+ } = props;
+
+ const uiOptions = getUiOptions(uiSchema);
+ const ArrayFieldDescriptionTemplate = getTemplate<'ArrayFieldDescriptionTemplate', T, S, F>(
+ 'ArrayFieldDescriptionTemplate',
+ registry,
+ uiOptions,
+ );
+ const ArrayFieldItemTemplate = getTemplate<'ArrayFieldItemTemplate', T, S, F>(
+ 'ArrayFieldItemTemplate',
+ registry,
+ uiOptions,
+ );
+ const ArrayFieldTitleTemplate = getTemplate<'ArrayFieldTitleTemplate', T, S, F>(
+ 'ArrayFieldTitleTemplate',
+ registry,
+ uiOptions,
+ );
+
+ return (
+ <>
+
+
+ >
+ );
+}
diff --git a/packages/primereact/src/ArrayFieldTemplate/index.ts b/packages/primereact/src/ArrayFieldTemplate/index.ts
new file mode 100644
index 0000000000..ab908dec2c
--- /dev/null
+++ b/packages/primereact/src/ArrayFieldTemplate/index.ts
@@ -0,0 +1,2 @@
+export { default } from './ArrayFieldTemplate';
+export * from './ArrayFieldTemplate';
diff --git a/packages/primereact/src/ArrayFieldTitleTemplate/ArrayFieldTitleTemplate.tsx b/packages/primereact/src/ArrayFieldTitleTemplate/ArrayFieldTitleTemplate.tsx
new file mode 100644
index 0000000000..785b5be60f
--- /dev/null
+++ b/packages/primereact/src/ArrayFieldTitleTemplate/ArrayFieldTitleTemplate.tsx
@@ -0,0 +1,25 @@
+import {
+ ArrayFieldTitleProps,
+ FormContextType,
+ getUiOptions,
+ RJSFSchema,
+ StrictRJSFSchema,
+ titleId,
+} from '@rjsf/utils';
+
+/** The `ArrayFieldTitleTemplate` component renders a header for the array.
+ *
+ * @param props - The `ArrayFieldTitleProps` for the component
+ */
+export default function ArrayFieldTitleTemplate<
+ T = any,
+ S extends StrictRJSFSchema = RJSFSchema,
+ F extends FormContextType = any,
+>({ title, uiSchema, required, idSchema }: ArrayFieldTitleProps) {
+ const uiOptions = getUiOptions(uiSchema);
+ return (
+
+ {uiOptions.title || title} {required ? '*' : ''}
+
+ );
+}
diff --git a/packages/primereact/src/ArrayFieldTitleTemplate/index.ts b/packages/primereact/src/ArrayFieldTitleTemplate/index.ts
new file mode 100644
index 0000000000..9893e24393
--- /dev/null
+++ b/packages/primereact/src/ArrayFieldTitleTemplate/index.ts
@@ -0,0 +1,2 @@
+export { default } from './ArrayFieldTitleTemplate';
+export * from './ArrayFieldTitleTemplate';
diff --git a/packages/primereact/src/AutoCompleteWidget/AutoCompleteWidget.tsx b/packages/primereact/src/AutoCompleteWidget/AutoCompleteWidget.tsx
new file mode 100644
index 0000000000..539182cd4a
--- /dev/null
+++ b/packages/primereact/src/AutoCompleteWidget/AutoCompleteWidget.tsx
@@ -0,0 +1,96 @@
+import { ChangeEvent, useState } from 'react';
+import {
+ ariaDescribedByIds,
+ FormContextType,
+ getInputProps,
+ RJSFSchema,
+ StrictRJSFSchema,
+ WidgetProps,
+} from '@rjsf/utils';
+import { AutoComplete, AutoCompleteCompleteEvent } from 'primereact/autocomplete';
+
+/** The `AutoCompleteWidget` is a widget for rendering a field with options.
+ * This is used instead of the base input template if the schema has examples.
+ *
+ * @param props - The `WidgetProps` for this component
+ */
+export default function AutoCompleteWidget<
+ T = any,
+ S extends StrictRJSFSchema = RJSFSchema,
+ F extends FormContextType = any,
+>(props: WidgetProps) {
+ const {
+ id,
+ placeholder,
+ value,
+ required,
+ readonly,
+ disabled,
+ onChange,
+ onChangeOverride,
+ onBlur,
+ onFocus,
+ autofocus,
+ options,
+ schema,
+ type,
+ rawErrors = [],
+ } = props;
+ const inputProps = getInputProps(schema, type, options);
+ const primeProps = (options.prime || {}) as object;
+ const _onChange = ({ target: { value } }: ChangeEvent) =>
+ onChange(value === '' ? options.emptyValue : value);
+ const _onBlur = () => onBlur && onBlur(id, value);
+ const _onFocus = () => onFocus && onFocus(id, value);
+
+ const examples = (schema.examples as string[]).concat(
+ schema.default && !(schema.examples as string[]).includes(schema.default.toString())
+ ? [schema.default.toString()]
+ : [],
+ );
+
+ const [items, setItems] = useState([]);
+
+ const search = (event: AutoCompleteCompleteEvent) => {
+ setItems(examples.filter((example) => example.toString().toLowerCase().includes(event.query.toLowerCase())));
+ };
+
+ return (
+ >}
+ required={required}
+ autoFocus={autofocus}
+ disabled={disabled || readonly}
+ suggestions={items}
+ completeMethod={search}
+ value={value || value === 0 ? value : ''}
+ dropdown
+ invalid={rawErrors.length > 0}
+ onChange={(onChangeOverride as any) || _onChange}
+ onBlur={_onBlur}
+ onFocus={_onFocus}
+ aria-describedby={ariaDescribedByIds(id, !!schema.examples)}
+ /* Make autocomplete look like a dropdown, which looks much nicer */
+ pt={{
+ root: {
+ className: 'p-dropdown',
+ },
+ input: {
+ root: {
+ style: { border: 'none' },
+ },
+ },
+ dropdownButton: {
+ root: {
+ className: 'p-button-text p-button-secondary',
+ },
+ },
+ }}
+ />
+ );
+}
diff --git a/packages/primereact/src/AutoCompleteWidget/index.ts b/packages/primereact/src/AutoCompleteWidget/index.ts
new file mode 100644
index 0000000000..a6c6ea9599
--- /dev/null
+++ b/packages/primereact/src/AutoCompleteWidget/index.ts
@@ -0,0 +1,2 @@
+export { default } from './AutoCompleteWidget';
+export * from './AutoCompleteWidget';
diff --git a/packages/primereact/src/BaseInputTemplate/BaseInputTemplate.tsx b/packages/primereact/src/BaseInputTemplate/BaseInputTemplate.tsx
new file mode 100644
index 0000000000..107387d494
--- /dev/null
+++ b/packages/primereact/src/BaseInputTemplate/BaseInputTemplate.tsx
@@ -0,0 +1,71 @@
+import { ChangeEvent } from 'react';
+import {
+ ariaDescribedByIds,
+ BaseInputTemplateProps,
+ examplesId,
+ FormContextType,
+ getInputProps,
+ RJSFSchema,
+ StrictRJSFSchema,
+} from '@rjsf/utils';
+import { InputText } from 'primereact/inputtext';
+
+/** The `BaseInputTemplate` is the template the fallback if no widget is specified.
+ */
+export default function BaseInputTemplate<
+ T = any,
+ S extends StrictRJSFSchema = RJSFSchema,
+ F extends FormContextType = any,
+>(props: BaseInputTemplateProps) {
+ const {
+ id,
+ placeholder,
+ value,
+ required,
+ readonly,
+ disabled,
+ onChange,
+ onChangeOverride,
+ onBlur,
+ onFocus,
+ autofocus,
+ options,
+ schema,
+ type,
+ registry,
+ rawErrors = [],
+ } = props;
+
+ const { AutoCompleteWidget } = registry.widgets;
+
+ if (Array.isArray(schema.examples)) {
+ return ;
+ }
+
+ const inputProps = getInputProps(schema, type, options);
+ const primeProps = (options.prime || {}) as object;
+ const _onChange = ({ target: { value } }: ChangeEvent) =>
+ onChange(value === '' ? options.emptyValue : value);
+ const _onBlur = () => onBlur && onBlur(id, value);
+ const _onFocus = () => onFocus && onFocus(id, value);
+
+ return (
+ (id) : undefined}
+ value={value || value === 0 ? value : ''}
+ invalid={rawErrors.length > 0}
+ onChange={onChangeOverride || _onChange}
+ onBlur={_onBlur}
+ onFocus={_onFocus}
+ aria-describedby={ariaDescribedByIds(id, !!schema.examples)}
+ />
+ );
+}
diff --git a/packages/primereact/src/BaseInputTemplate/index.ts b/packages/primereact/src/BaseInputTemplate/index.ts
new file mode 100644
index 0000000000..f7ef8d5939
--- /dev/null
+++ b/packages/primereact/src/BaseInputTemplate/index.ts
@@ -0,0 +1,2 @@
+export { default } from './BaseInputTemplate';
+export * from './BaseInputTemplate';
diff --git a/packages/primereact/src/CheckboxWidget/CheckboxWidget.tsx b/packages/primereact/src/CheckboxWidget/CheckboxWidget.tsx
new file mode 100644
index 0000000000..7bd051228a
--- /dev/null
+++ b/packages/primereact/src/CheckboxWidget/CheckboxWidget.tsx
@@ -0,0 +1,86 @@
+import {
+ ariaDescribedByIds,
+ descriptionId,
+ getTemplate,
+ labelValue,
+ schemaRequiresTrueValue,
+ FormContextType,
+ RJSFSchema,
+ StrictRJSFSchema,
+ WidgetProps,
+} from '@rjsf/utils';
+import { Checkbox, CheckboxChangeEvent } from 'primereact/checkbox';
+
+import { Label } from '../util';
+
+/** The `CheckBoxWidget` is a widget for rendering boolean properties.
+ * It is typically used to represent a boolean.
+ *
+ * @param props - The `WidgetProps` for this component
+ */
+export default function CheckboxWidget<
+ T = any,
+ S extends StrictRJSFSchema = RJSFSchema,
+ F extends FormContextType = any,
+>(props: WidgetProps) {
+ const {
+ id,
+ value,
+ disabled,
+ readonly,
+ label = '',
+ hideLabel,
+ autofocus,
+ onChange,
+ onBlur,
+ options,
+ onFocus,
+ schema,
+ uiSchema,
+ registry,
+ } = props;
+
+ const DescriptionFieldTemplate = getTemplate<'DescriptionFieldTemplate', T, S, F>(
+ 'DescriptionFieldTemplate',
+ registry,
+ options,
+ );
+
+ const required = schemaRequiresTrueValue(schema);
+ const _onChange = (e: CheckboxChangeEvent) => onChange && onChange(e.checked);
+ const _onBlur = () => onBlur && onBlur(id, value);
+ const _onFocus = () => onFocus && onFocus(id, value);
+ const checked = value === 'true' || value === true;
+ const description = options.description ?? schema.description;
+ const primeProps = (options.prime || {}) as object;
+
+ return (
+ <>
+ {!hideLabel && !!description && (
+ (id)}
+ description={description}
+ schema={schema}
+ uiSchema={uiSchema}
+ registry={registry}
+ />
+ )}
+
+ (id)}
+ />
+ {labelValue(, hideLabel, false)}
+
+ >
+ );
+}
diff --git a/packages/primereact/src/CheckboxWidget/index.ts b/packages/primereact/src/CheckboxWidget/index.ts
new file mode 100644
index 0000000000..b9e3c318ec
--- /dev/null
+++ b/packages/primereact/src/CheckboxWidget/index.ts
@@ -0,0 +1,2 @@
+export { default } from './CheckboxWidget';
+export * from './CheckboxWidget';
diff --git a/packages/primereact/src/CheckboxesWidget/CheckboxesWidget.tsx b/packages/primereact/src/CheckboxesWidget/CheckboxesWidget.tsx
new file mode 100644
index 0000000000..8ed252ac96
--- /dev/null
+++ b/packages/primereact/src/CheckboxesWidget/CheckboxesWidget.tsx
@@ -0,0 +1,105 @@
+import { Checkbox, CheckboxChangeEvent } from 'primereact/checkbox';
+import {
+ ariaDescribedByIds,
+ enumOptionsDeselectValue,
+ enumOptionsIsSelected,
+ enumOptionsSelectValue,
+ optionId,
+ FormContextType,
+ RJSFSchema,
+ StrictRJSFSchema,
+ WidgetProps,
+ descriptionId,
+ getTemplate,
+} from '@rjsf/utils';
+
+import { Label } from '../util';
+
+/** The `CheckboxesWidget` is a widget for rendering checkbox groups.
+ * It is typically used to represent an array of enums.
+ *
+ * @param props - The `WidgetProps` for this component
+ */
+export default function CheckboxesWidget<
+ T = any,
+ S extends StrictRJSFSchema = RJSFSchema,
+ F extends FormContextType = any,
+>(props: WidgetProps) {
+ const {
+ id,
+ disabled,
+ options,
+ value,
+ autofocus,
+ readonly,
+ onChange,
+ onBlur,
+ onFocus,
+ schema,
+ uiSchema,
+ registry,
+ hideLabel,
+ } = props;
+ const { enumOptions, enumDisabled } = options;
+ const primeProps = (options.prime || {}) as object;
+ const checkboxesValues = Array.isArray(value) ? value : [value];
+
+ const _onChange = (index: number) => (e: CheckboxChangeEvent) => {
+ if (e.checked) {
+ onChange(enumOptionsSelectValue(index, checkboxesValues, enumOptions));
+ } else {
+ onChange(enumOptionsDeselectValue(index, checkboxesValues, enumOptions));
+ }
+ };
+
+ const DescriptionFieldTemplate = getTemplate<'DescriptionFieldTemplate', T, S, F>(
+ 'DescriptionFieldTemplate',
+ registry,
+ options,
+ );
+
+ const _onBlur = () => onBlur(id, value);
+ const _onFocus = () => onFocus(id, value);
+
+ const description = options.description ?? schema.description;
+
+ return (
+
+ {!hideLabel && !!description && (
+
(id)}
+ description={description}
+ schema={schema}
+ uiSchema={uiSchema}
+ registry={registry}
+ />
+ )}
+ {Array.isArray(enumOptions) &&
+ enumOptions.map((option, index) => {
+ const checked = enumOptionsIsSelected(option.value, checkboxesValues);
+ const itemDisabled = Array.isArray(enumDisabled) && enumDisabled.indexOf(option.value) !== -1;
+ return (
+
+ (id)}
+ />
+
+
+ );
+ })}
+
+ );
+}
diff --git a/packages/primereact/src/CheckboxesWidget/index.ts b/packages/primereact/src/CheckboxesWidget/index.ts
new file mode 100644
index 0000000000..97152004fa
--- /dev/null
+++ b/packages/primereact/src/CheckboxesWidget/index.ts
@@ -0,0 +1,2 @@
+export { default } from './CheckboxesWidget';
+export * from './CheckboxesWidget';
diff --git a/packages/primereact/src/ColorWidget/ColorWidget.tsx b/packages/primereact/src/ColorWidget/ColorWidget.tsx
new file mode 100644
index 0000000000..529c0183e8
--- /dev/null
+++ b/packages/primereact/src/ColorWidget/ColorWidget.tsx
@@ -0,0 +1,62 @@
+import { ChangeEvent } from 'react';
+import {
+ ariaDescribedByIds,
+ FormContextType,
+ getInputProps,
+ RJSFSchema,
+ StrictRJSFSchema,
+ WidgetProps,
+} from '@rjsf/utils';
+import { ColorPicker } from 'primereact/colorpicker';
+
+/** The `ColorWidget` component renders a color picker.
+ *
+ * @param props - The `WidgetProps` for this component
+ */
+export default function ColorWidget(
+ props: WidgetProps,
+) {
+ const {
+ id,
+ placeholder,
+ value,
+ required,
+ readonly,
+ disabled,
+ onChange,
+ onChangeOverride,
+ onBlur,
+ onFocus,
+ autofocus,
+ options,
+ schema,
+ type,
+ } = props;
+ const inputProps = getInputProps(schema, type, options);
+ const { inline } = options;
+ const primeProps = (options.prime || {}) as object;
+
+ const _onChange = ({ target: { value } }: ChangeEvent) =>
+ onChange(value === '' ? options.emptyValue : value);
+ const _onBlur = () => onBlur && onBlur(id, value);
+ const _onFocus = () => onFocus && onFocus(id, value);
+
+ return (
+ (id, !!schema.examples)}
+ />
+ );
+}
diff --git a/packages/primereact/src/ColorWidget/index.ts b/packages/primereact/src/ColorWidget/index.ts
new file mode 100644
index 0000000000..9d202495a3
--- /dev/null
+++ b/packages/primereact/src/ColorWidget/index.ts
@@ -0,0 +1,2 @@
+export { default } from './ColorWidget';
+export * from './ColorWidget';
diff --git a/packages/primereact/src/DescriptionField/DescriptionField.tsx b/packages/primereact/src/DescriptionField/DescriptionField.tsx
new file mode 100644
index 0000000000..6189ab2472
--- /dev/null
+++ b/packages/primereact/src/DescriptionField/DescriptionField.tsx
@@ -0,0 +1,22 @@
+import { DescriptionFieldProps, FormContextType, RJSFSchema, StrictRJSFSchema } from '@rjsf/utils';
+import { RichDescription } from '@rjsf/core';
+
+/** The `DescriptionField` is the template to use to render the description of a field
+ *
+ * @param props - The `DescriptionFieldProps` for this component
+ */
+export default function DescriptionField<
+ T = any,
+ S extends StrictRJSFSchema = RJSFSchema,
+ F extends FormContextType = any,
+>(props: DescriptionFieldProps) {
+ const { id, description, registry, uiSchema } = props;
+ if (!description) {
+ return null;
+ }
+ return (
+
+
+
+ );
+}
diff --git a/packages/primereact/src/DescriptionField/index.ts b/packages/primereact/src/DescriptionField/index.ts
new file mode 100644
index 0000000000..401540d99b
--- /dev/null
+++ b/packages/primereact/src/DescriptionField/index.ts
@@ -0,0 +1,2 @@
+export { default } from './DescriptionField';
+export * from './DescriptionField';
diff --git a/packages/primereact/src/ErrorList/ErrorList.tsx b/packages/primereact/src/ErrorList/ErrorList.tsx
new file mode 100644
index 0000000000..8bfede575c
--- /dev/null
+++ b/packages/primereact/src/ErrorList/ErrorList.tsx
@@ -0,0 +1,44 @@
+import { Message } from 'primereact/message';
+import { TimesCircleIcon } from 'primereact/icons/timescircle';
+import { ErrorListProps, FormContextType, RJSFSchema, StrictRJSFSchema, TranslatableString } from '@rjsf/utils';
+
+/** The `ErrorList` component is the template that renders all the errors associated with the fields in the `Form`
+ *
+ * @param props - The `ErrorListProps` for this component
+ */
+export default function ErrorList({
+ errors,
+ registry,
+}: ErrorListProps) {
+ const { translateString } = registry;
+
+ const content = (
+
+
+
+
{translateString(TranslatableString.ErrorsLabel)}
+
+
+ {errors.map((error, index) => (
+ - {error.stack}
+ ))}
+
+
+ );
+
+ return (
+
+ );
+}
diff --git a/packages/primereact/src/ErrorList/index.ts b/packages/primereact/src/ErrorList/index.ts
new file mode 100644
index 0000000000..79376ace11
--- /dev/null
+++ b/packages/primereact/src/ErrorList/index.ts
@@ -0,0 +1,2 @@
+export { default } from './ErrorList';
+export * from './ErrorList';
diff --git a/packages/primereact/src/FieldErrorTemplate/FieldErrorTemplate.tsx b/packages/primereact/src/FieldErrorTemplate/FieldErrorTemplate.tsx
new file mode 100644
index 0000000000..0f4c03714a
--- /dev/null
+++ b/packages/primereact/src/FieldErrorTemplate/FieldErrorTemplate.tsx
@@ -0,0 +1,30 @@
+import { errorId, FieldErrorProps, FormContextType, RJSFSchema, StrictRJSFSchema } from '@rjsf/utils';
+import { Message } from 'primereact/message';
+
+/** The `FieldErrorTemplate` component renders the errors local to the particular field
+ *
+ * @param props - The `FieldErrorProps` for the errors being rendered
+ */
+export default function FieldErrorTemplate<
+ T = any,
+ S extends StrictRJSFSchema = RJSFSchema,
+ F extends FormContextType = any,
+>({ errors, idSchema }: FieldErrorProps) {
+ if (errors && errors.length > 0) {
+ const id = errorId(idSchema);
+ const content = errors.map((error, i: number) => {
+ return {error}
;
+ });
+
+ return (
+
+ );
+ }
+ return null;
+}
diff --git a/packages/primereact/src/FieldErrorTemplate/index.ts b/packages/primereact/src/FieldErrorTemplate/index.ts
new file mode 100644
index 0000000000..2fbf1c353d
--- /dev/null
+++ b/packages/primereact/src/FieldErrorTemplate/index.ts
@@ -0,0 +1,2 @@
+export { default } from './FieldErrorTemplate';
+export * from './FieldErrorTemplate';
diff --git a/packages/primereact/src/FieldHelpTemplate/FieldHelpTemplate.tsx b/packages/primereact/src/FieldHelpTemplate/FieldHelpTemplate.tsx
new file mode 100644
index 0000000000..52e1ebd973
--- /dev/null
+++ b/packages/primereact/src/FieldHelpTemplate/FieldHelpTemplate.tsx
@@ -0,0 +1,18 @@
+import { FieldHelpProps, FormContextType, RJSFSchema, StrictRJSFSchema, helpId } from '@rjsf/utils';
+
+/** The `FieldHelpTemplate` component renders any help desired for a field
+ *
+ * @param props - The `FieldHelpProps` to be rendered
+ */
+export default function FieldHelpTemplate<
+ T = any,
+ S extends StrictRJSFSchema = RJSFSchema,
+ F extends FormContextType = any,
+>(props: FieldHelpProps) {
+ const { idSchema, help } = props;
+ if (help) {
+ const id = helpId(idSchema);
+ return {help};
+ }
+ return null;
+}
diff --git a/packages/primereact/src/FieldHelpTemplate/index.ts b/packages/primereact/src/FieldHelpTemplate/index.ts
new file mode 100644
index 0000000000..b439bce3f1
--- /dev/null
+++ b/packages/primereact/src/FieldHelpTemplate/index.ts
@@ -0,0 +1,2 @@
+export { default } from './FieldHelpTemplate';
+export * from './FieldHelpTemplate';
diff --git a/packages/primereact/src/FieldTemplate/FieldTemplate.tsx b/packages/primereact/src/FieldTemplate/FieldTemplate.tsx
new file mode 100644
index 0000000000..c3c1b6131d
--- /dev/null
+++ b/packages/primereact/src/FieldTemplate/FieldTemplate.tsx
@@ -0,0 +1,40 @@
+import {
+ FieldTemplateProps,
+ FormContextType,
+ getTemplate,
+ getUiOptions,
+ RJSFSchema,
+ StrictRJSFSchema,
+} from '@rjsf/utils';
+
+import { Label } from '../util';
+
+export default function FieldTemplate<
+ T = any,
+ S extends StrictRJSFSchema = RJSFSchema,
+ F extends FormContextType = any,
+>(props: FieldTemplateProps) {
+ const { children, errors, help, displayLabel, description, rawDescription, hidden, uiSchema, registry } = props;
+ const uiOptions = getUiOptions(uiSchema);
+ const WrapIfAdditionalTemplate = getTemplate<'WrapIfAdditionalTemplate', T, S, F>(
+ 'WrapIfAdditionalTemplate',
+ registry,
+ uiOptions,
+ );
+
+ if (hidden) {
+ return {children}
;
+ }
+
+ return (
+
+
+ {displayLabel && }
+ {children}
+ {displayLabel && rawDescription && {description}}
+ {errors}
+ {help}
+
+
+ );
+}
diff --git a/packages/primereact/src/FieldTemplate/index.ts b/packages/primereact/src/FieldTemplate/index.ts
new file mode 100644
index 0000000000..6f7dc3861c
--- /dev/null
+++ b/packages/primereact/src/FieldTemplate/index.ts
@@ -0,0 +1,2 @@
+export { default } from './FieldTemplate';
+export * from './FieldTemplate';
diff --git a/packages/primereact/src/GridTemplate/GridTemplate.tsx b/packages/primereact/src/GridTemplate/GridTemplate.tsx
new file mode 100644
index 0000000000..4faa34af2e
--- /dev/null
+++ b/packages/primereact/src/GridTemplate/GridTemplate.tsx
@@ -0,0 +1,93 @@
+import { useEffect, useState } from 'react';
+import { GridTemplateProps } from '@rjsf/utils';
+
+const breakpoints = {
+ xs: 0,
+ sm: 576,
+ md: 768,
+ lg: 992,
+ xl: 1200,
+};
+
+type Breakpoint = keyof typeof breakpoints;
+type ResponsiveSpan = Partial>;
+
+function getBreakpoint(width: number): Breakpoint {
+ if (width >= breakpoints.xl) {
+ return 'xl';
+ }
+ if (width >= breakpoints.lg) {
+ return 'lg';
+ }
+ if (width >= breakpoints.md) {
+ return 'md';
+ }
+ if (width >= breakpoints.sm) {
+ return 'sm';
+ }
+ return 'xs';
+}
+
+function getResponsiveSpan(spanDef: ResponsiveSpan, breakpoint: Breakpoint): number {
+ return spanDef[breakpoint] ?? spanDef.xl ?? spanDef.lg ?? spanDef.md ?? spanDef.sm ?? spanDef.xs ?? 12;
+}
+
+function getInitialWidth(): number {
+ return typeof window !== 'undefined' ? window.innerWidth : breakpoints.xs;
+}
+
+/** Renders a `GridTemplate`, which is expecting the column size for each viewport breakpoint (xs, sm, md, lg, xl)
+ * coming in via the extra props provided by the caller.
+ * Uses a 12 column grid by default. This can be overridden by passing `layoutGrid` in `uiSchema`.
+ *
+ * @param props - The GridTemplateProps, including the extra props containing the grid sizing details
+ */
+export default function GridTemplate(props: GridTemplateProps) {
+ return props.column ? GridTemplateColumn(props) : GridTemplateRow(props);
+}
+
+function GridTemplateRow(props: GridTemplateProps) {
+ const { children, column, uiSchema, style, ...rest } = props;
+ const layoutGrid = uiSchema?.['ui:layoutGrid'] ?? {};
+ const totalColumns = layoutGrid.columns ?? 12;
+ const gap = layoutGrid.gap ?? '16px';
+
+ return (
+
+ {children}
+
+ );
+}
+
+function GridTemplateColumn(props: GridTemplateProps) {
+ const { children, column, uiSchema, xs, sm, md, lg, xl, style, ...rest } = props;
+
+ const [breakpoint, setBreakpoint] = useState(() => getBreakpoint(getInitialWidth()));
+
+ useEffect(() => {
+ if (typeof window === 'undefined') {
+ return;
+ }
+
+ const handleResize = () => setBreakpoint(getBreakpoint(window.innerWidth));
+ window.addEventListener('resize', handleResize);
+ return () => window.removeEventListener('resize', handleResize);
+ }, []);
+
+ const span = getResponsiveSpan(props as ResponsiveSpan, breakpoint);
+
+ return (
+
+ {children}
+
+ );
+}
diff --git a/packages/primereact/src/GridTemplate/index.ts b/packages/primereact/src/GridTemplate/index.ts
new file mode 100644
index 0000000000..ed6c2c4fc5
--- /dev/null
+++ b/packages/primereact/src/GridTemplate/index.ts
@@ -0,0 +1,2 @@
+export { default } from './GridTemplate';
+export * from './GridTemplate';
diff --git a/packages/primereact/src/IconButton/IconButton.tsx b/packages/primereact/src/IconButton/IconButton.tsx
new file mode 100644
index 0000000000..a084cacceb
--- /dev/null
+++ b/packages/primereact/src/IconButton/IconButton.tsx
@@ -0,0 +1,47 @@
+import { Button } from 'primereact/button';
+import { FormContextType, IconButtonProps, RJSFSchema, StrictRJSFSchema, TranslatableString } from '@rjsf/utils';
+
+function IconButton(
+ props: IconButtonProps,
+) {
+ const { icon, iconType, uiSchema, registry, ...otherProps } = props;
+ return ;
+}
+
+export default IconButton;
+
+export function CopyButton(
+ props: IconButtonProps,
+) {
+ const {
+ registry: { translateString },
+ } = props;
+ return ;
+}
+
+export function MoveDownButton(
+ props: IconButtonProps,
+) {
+ const {
+ registry: { translateString },
+ } = props;
+ return ;
+}
+
+export function MoveUpButton(
+ props: IconButtonProps,
+) {
+ const {
+ registry: { translateString },
+ } = props;
+ return ;
+}
+
+export function RemoveButton(
+ props: IconButtonProps,
+) {
+ const {
+ registry: { translateString },
+ } = props;
+ return ;
+}
diff --git a/packages/primereact/src/IconButton/index.ts b/packages/primereact/src/IconButton/index.ts
new file mode 100644
index 0000000000..655ec4c488
--- /dev/null
+++ b/packages/primereact/src/IconButton/index.ts
@@ -0,0 +1,2 @@
+export { default } from './IconButton';
+export * from './IconButton';
diff --git a/packages/primereact/src/ObjectFieldTemplate/ObjectFieldTemplate.tsx b/packages/primereact/src/ObjectFieldTemplate/ObjectFieldTemplate.tsx
new file mode 100644
index 0000000000..0d6f05d7cc
--- /dev/null
+++ b/packages/primereact/src/ObjectFieldTemplate/ObjectFieldTemplate.tsx
@@ -0,0 +1,88 @@
+import {
+ FormContextType,
+ ObjectFieldTemplateProps,
+ RJSFSchema,
+ StrictRJSFSchema,
+ canExpand,
+ descriptionId,
+ getTemplate,
+ getUiOptions,
+ titleId,
+ buttonId,
+} from '@rjsf/utils';
+
+/** The `ObjectFieldTemplate` is the template to use to render all the inner properties of an object along with the
+ * title and description if available. If the object is expandable, then an `AddButton` is also rendered after all
+ * the properties.
+ *
+ * @param props - The `ObjectFieldTemplateProps` for this component
+ */
+export default function ObjectFieldTemplate<
+ T = any,
+ S extends StrictRJSFSchema = RJSFSchema,
+ F extends FormContextType = any,
+>(props: ObjectFieldTemplateProps) {
+ const {
+ description,
+ onAddClick,
+ title,
+ properties,
+ disabled,
+ readonly,
+ required,
+ uiSchema,
+ schema,
+ formData,
+ idSchema,
+ registry,
+ } = props;
+ const uiOptions = getUiOptions(uiSchema);
+ const TitleFieldTemplate = getTemplate<'TitleFieldTemplate', T, S, F>('TitleFieldTemplate', registry, uiOptions);
+ const DescriptionFieldTemplate = getTemplate<'DescriptionFieldTemplate', T, S, F>(
+ 'DescriptionFieldTemplate',
+ registry,
+ uiOptions,
+ );
+ // Button templates are not overridden in the uiSchema
+ const {
+ ButtonTemplates: { AddButton },
+ } = registry.templates;
+ return (
+ <>
+ {title && (
+ (idSchema)}
+ title={title}
+ required={required}
+ schema={schema}
+ uiSchema={uiSchema}
+ registry={registry}
+ />
+ )}
+ {description && (
+
+ (idSchema)}
+ description={description}
+ schema={schema}
+ uiSchema={uiSchema}
+ registry={registry}
+ />
+
+ )}
+ {properties.map((prop) => prop.content)}
+ {canExpand(schema, uiSchema, formData) && (
+
+
(idSchema, 'add')}
+ className='rjsf-object-property-expand'
+ icon='pi pi-plus'
+ onClick={onAddClick(schema)}
+ disabled={disabled || readonly}
+ registry={registry}
+ />
+
+ )}
+ >
+ );
+}
diff --git a/packages/primereact/src/ObjectFieldTemplate/index.ts b/packages/primereact/src/ObjectFieldTemplate/index.ts
new file mode 100644
index 0000000000..77c68a9a40
--- /dev/null
+++ b/packages/primereact/src/ObjectFieldTemplate/index.ts
@@ -0,0 +1,2 @@
+export { default } from './ObjectFieldTemplate';
+export * from './ObjectFieldTemplate';
diff --git a/packages/primereact/src/PasswordWidget/PasswordWidget.tsx b/packages/primereact/src/PasswordWidget/PasswordWidget.tsx
new file mode 100644
index 0000000000..d12363693b
--- /dev/null
+++ b/packages/primereact/src/PasswordWidget/PasswordWidget.tsx
@@ -0,0 +1,65 @@
+import { ChangeEvent } from 'react';
+import {
+ ariaDescribedByIds,
+ FormContextType,
+ getInputProps,
+ RJSFSchema,
+ StrictRJSFSchema,
+ WidgetProps,
+} from '@rjsf/utils';
+import { Password } from 'primereact/password';
+
+/** The `PasswordWidget` renders a `Password` component
+ *
+ * @param props - The `WidgetProps` for this component
+ */
+export default function PasswordWidget<
+ T = any,
+ S extends StrictRJSFSchema = RJSFSchema,
+ F extends FormContextType = any,
+>(props: WidgetProps) {
+ const {
+ id,
+ placeholder,
+ value,
+ required,
+ readonly,
+ disabled,
+ onChange,
+ onChangeOverride,
+ onBlur,
+ onFocus,
+ autofocus,
+ options,
+ schema,
+ type,
+ rawErrors = [],
+ } = props;
+ const inputProps = getInputProps(schema, type, options);
+ const primeProps = (options.prime || {}) as object;
+
+ const _onChange = ({ target: { value } }: ChangeEvent) =>
+ onChange(value === '' ? options.emptyValue : value);
+ const _onBlur = () => onBlur && onBlur(id, value);
+ const _onFocus = () => onFocus && onFocus(id, value);
+
+ return (
+ 0}
+ onChange={onChangeOverride || _onChange}
+ onBlur={_onBlur}
+ onFocus={_onFocus}
+ aria-describedby={ariaDescribedByIds(id, !!schema.examples)}
+ pt={{ root: { style: { display: 'flex', flexDirection: 'column' } } }}
+ />
+ );
+}
diff --git a/packages/primereact/src/PasswordWidget/index.ts b/packages/primereact/src/PasswordWidget/index.ts
new file mode 100644
index 0000000000..84fd5e9026
--- /dev/null
+++ b/packages/primereact/src/PasswordWidget/index.ts
@@ -0,0 +1,2 @@
+export { default } from './PasswordWidget';
+export * from './PasswordWidget';
diff --git a/packages/primereact/src/PrimeForm/PrimeForm.ts b/packages/primereact/src/PrimeForm/PrimeForm.ts
new file mode 100644
index 0000000000..0d1c71265f
--- /dev/null
+++ b/packages/primereact/src/PrimeForm/PrimeForm.ts
@@ -0,0 +1,15 @@
+import { ComponentType } from 'react';
+import { withTheme, FormProps } from '@rjsf/core';
+import { FormContextType, RJSFSchema, StrictRJSFSchema } from '@rjsf/utils';
+
+import { generateTheme } from '../Theme';
+
+export function generateForm<
+ T = any,
+ S extends StrictRJSFSchema = RJSFSchema,
+ F extends FormContextType = any,
+>(): ComponentType> {
+ return withTheme(generateTheme());
+}
+
+export default generateForm();
diff --git a/packages/primereact/src/PrimeForm/index.ts b/packages/primereact/src/PrimeForm/index.ts
new file mode 100644
index 0000000000..c33c2151a8
--- /dev/null
+++ b/packages/primereact/src/PrimeForm/index.ts
@@ -0,0 +1,2 @@
+export { default } from './PrimeForm';
+export * from './PrimeForm';
diff --git a/packages/primereact/src/RadioWidget/RadioWidget.tsx b/packages/primereact/src/RadioWidget/RadioWidget.tsx
new file mode 100644
index 0000000000..99655a31ab
--- /dev/null
+++ b/packages/primereact/src/RadioWidget/RadioWidget.tsx
@@ -0,0 +1,60 @@
+import {
+ ariaDescribedByIds,
+ enumOptionsIsSelected,
+ enumOptionsValueForIndex,
+ optionId,
+ FormContextType,
+ RJSFSchema,
+ StrictRJSFSchema,
+ WidgetProps,
+} from '@rjsf/utils';
+import { RadioButton, RadioButtonChangeEvent } from 'primereact/radiobutton';
+
+/** The `RadioWidget` is a widget for rendering a radio group.
+ * It is typically used with a string property constrained with enum options.
+ *
+ * @param props - The `WidgetProps` for this component
+ */
+export default function RadioWidget(
+ props: WidgetProps,
+) {
+ const { id, value, disabled, readonly, onChange, onBlur, onFocus, options } = props;
+ const primeProps = (options.prime || {}) as object;
+ const { enumOptions, enumDisabled, emptyValue } = options;
+
+ const _onChange = (e: RadioButtonChangeEvent) => {
+ onChange(enumOptionsValueForIndex(e.value, enumOptions, emptyValue));
+ };
+
+ const _onBlur = () => onBlur(id, value);
+ const _onFocus = () => onFocus(id, value);
+
+ return (
+
+ {Array.isArray(enumOptions) &&
+ enumOptions.map((option, index) => {
+ const checked = enumOptionsIsSelected
(option.value, value);
+ const itemDisabled = Array.isArray(enumDisabled) && enumDisabled.indexOf(option.value) !== -1;
+ return (
+
+ (id)}
+ />
+
+
+ );
+ })}
+
+ );
+}
diff --git a/packages/primereact/src/RadioWidget/index.ts b/packages/primereact/src/RadioWidget/index.ts
new file mode 100644
index 0000000000..10292dc565
--- /dev/null
+++ b/packages/primereact/src/RadioWidget/index.ts
@@ -0,0 +1,2 @@
+export { default } from './RadioWidget';
+export * from './RadioWidget';
diff --git a/packages/primereact/src/RangeWidget/RangeWidget.tsx b/packages/primereact/src/RangeWidget/RangeWidget.tsx
new file mode 100644
index 0000000000..b7e86a7492
--- /dev/null
+++ b/packages/primereact/src/RangeWidget/RangeWidget.tsx
@@ -0,0 +1,37 @@
+import { FocusEvent } from 'react';
+import { Slider, SliderChangeEvent } from 'primereact/slider';
+import { ariaDescribedByIds, FormContextType, RJSFSchema, StrictRJSFSchema, WidgetProps, rangeSpec } from '@rjsf/utils';
+
+/** The `RangeWidget` component uses the `Slider` from PrimeReact, wrapping the result
+ * in a div, with the value alongside it.
+ *
+ * @param props - The `WidgetProps` for this component
+ */
+export default function RangeWidget(
+ props: WidgetProps,
+) {
+ const { value, readonly, disabled, onBlur, onFocus, options, schema, onChange, id } = props;
+ const primeProps = (options.prime || {}) as object;
+ const sliderProps = { value, id, ...rangeSpec(schema) };
+
+ const _onChange = (e: SliderChangeEvent) => {
+ onChange(e.value ?? options.emptyValue);
+ };
+ const _onBlur = ({ target }: FocusEvent) => onBlur(id, target && target.value);
+ const _onFocus = ({ target }: FocusEvent) => onFocus(id, target && target.value);
+
+ return (
+ <>
+ e.stopPropagation()}
+ onChange={_onChange}
+ onBlur={_onBlur}
+ onFocus={_onFocus}
+ {...sliderProps}
+ aria-describedby={ariaDescribedByIds(id)}
+ />
+ >
+ );
+}
diff --git a/packages/primereact/src/RangeWidget/index.ts b/packages/primereact/src/RangeWidget/index.ts
new file mode 100644
index 0000000000..d8c49226c6
--- /dev/null
+++ b/packages/primereact/src/RangeWidget/index.ts
@@ -0,0 +1,2 @@
+export { default } from './RangeWidget';
+export * from './RangeWidget';
diff --git a/packages/primereact/src/SelectWidget/SelectWidget.tsx b/packages/primereact/src/SelectWidget/SelectWidget.tsx
new file mode 100644
index 0000000000..67f3263f7e
--- /dev/null
+++ b/packages/primereact/src/SelectWidget/SelectWidget.tsx
@@ -0,0 +1,139 @@
+import { FocusEvent } from 'react';
+import { Dropdown } from 'primereact/dropdown';
+import {
+ ariaDescribedByIds,
+ enumOptionsIndexForValue,
+ enumOptionsValueForIndex,
+ FormContextType,
+ RJSFSchema,
+ StrictRJSFSchema,
+ WidgetProps,
+} from '@rjsf/utils';
+import { MultiSelect } from 'primereact/multiselect';
+
+/** The `SelectWidget` is a widget for rendering dropdowns.
+ * It is typically used with string properties constrained with enum options.
+ *
+ * @param props - The `WidgetProps` for this component
+ */
+export default function SelectWidget(
+ props: WidgetProps,
+) {
+ const { multiple = false } = props;
+
+ return multiple ? : ;
+}
+
+function SingleSelectWidget({
+ schema,
+ id,
+ name, // remove this from dropdownProps
+ options,
+ label,
+ hideLabel,
+ required,
+ disabled,
+ placeholder,
+ readonly,
+ value,
+ multiple,
+ autofocus,
+ onChange,
+ onBlur,
+ onFocus,
+ errorSchema,
+ rawErrors = [],
+ registry,
+ uiSchema,
+ hideError,
+ formContext,
+ ...dropdownProps
+}: WidgetProps) {
+ const { enumOptions, enumDisabled, emptyValue: optEmptyVal } = options;
+ const primeProps = (options.prime || {}) as object;
+
+ multiple = typeof multiple === 'undefined' ? false : multiple;
+
+ const emptyValue = multiple ? [] : '';
+ const isEmpty = typeof value === 'undefined' || (multiple && value.length < 1) || (!multiple && value === emptyValue);
+
+ const _onChange = (e: { value: any }) => onChange(enumOptionsValueForIndex(e.value, enumOptions, optEmptyVal));
+ const _onBlur = ({ target }: FocusEvent) =>
+ onBlur(id, enumOptionsValueForIndex(target && target.value, enumOptions, optEmptyVal));
+ const _onFocus = ({ target }: FocusEvent) =>
+ onFocus(id, enumOptionsValueForIndex(target && target.value, enumOptions, optEmptyVal));
+ const selectedIndexes = enumOptionsIndexForValue(value, enumOptions, multiple);
+ const { ...dropdownRemainingProps } = dropdownProps;
+
+ return (
+ ({
+ label,
+ value: String(i),
+ disabled: Array.isArray(enumDisabled) && enumDisabled.indexOf(value) !== -1,
+ }))}
+ onChange={_onChange}
+ onBlur={_onBlur}
+ onFocus={_onFocus}
+ placeholder={placeholder}
+ disabled={disabled || readonly}
+ autoFocus={autofocus}
+ aria-describedby={ariaDescribedByIds(id)}
+ {...dropdownRemainingProps}
+ />
+ );
+}
+
+function MultiSelectWidget({
+ id,
+ options,
+ disabled,
+ placeholder,
+ readonly,
+ value,
+ multiple = false,
+ autofocus,
+ onChange,
+ onBlur,
+ onFocus,
+}: WidgetProps) {
+ const { enumOptions, enumDisabled, emptyValue: optEmptyVal } = options;
+ const primeProps = (options.prime || {}) as object;
+
+ const emptyValue = multiple ? [] : '';
+ const isEmpty = typeof value === 'undefined' || (multiple && value.length < 1) || (!multiple && value === emptyValue);
+
+ const _onChange = (e: { value: any }) => onChange(enumOptionsValueForIndex(e.value, enumOptions, optEmptyVal));
+ const _onBlur = ({ target }: FocusEvent) =>
+ onBlur(id, enumOptionsValueForIndex(target && target.value, enumOptions, optEmptyVal));
+ const _onFocus = ({ target }: FocusEvent) =>
+ onFocus(id, enumOptionsValueForIndex(target && target.value, enumOptions, optEmptyVal));
+ const selectedIndexes = enumOptionsIndexForValue(value, enumOptions, multiple);
+
+ return (
+ ({
+ label,
+ value: String(i),
+ disabled: Array.isArray(enumDisabled) && enumDisabled.indexOf(value) !== -1,
+ }))}
+ onChange={_onChange}
+ onBlur={_onBlur}
+ onFocus={_onFocus}
+ placeholder={placeholder}
+ disabled={disabled || readonly}
+ autoFocus={autofocus}
+ display={options.display === 'chip' ? 'chip' : 'comma'}
+ aria-describedby={ariaDescribedByIds(id)}
+ pt={{ root: { style: { position: 'relative' } } }}
+ />
+ );
+}
diff --git a/packages/primereact/src/SelectWidget/index.ts b/packages/primereact/src/SelectWidget/index.ts
new file mode 100644
index 0000000000..e37ea725b8
--- /dev/null
+++ b/packages/primereact/src/SelectWidget/index.ts
@@ -0,0 +1,2 @@
+export { default } from './SelectWidget';
+export * from './SelectWidget';
diff --git a/packages/primereact/src/SubmitButton/SubmitButton.tsx b/packages/primereact/src/SubmitButton/SubmitButton.tsx
new file mode 100644
index 0000000000..641aa04c6f
--- /dev/null
+++ b/packages/primereact/src/SubmitButton/SubmitButton.tsx
@@ -0,0 +1,16 @@
+import { Button } from 'primereact/button';
+import { getSubmitButtonOptions, FormContextType, RJSFSchema, StrictRJSFSchema, SubmitButtonProps } from '@rjsf/utils';
+
+/** The `SubmitButton` renders a button that represents the `Submit` action on a form
+ */
+export default function SubmitButton<
+ T = any,
+ S extends StrictRJSFSchema = RJSFSchema,
+ F extends FormContextType = any,
+>({ uiSchema }: SubmitButtonProps) {
+ const { submitText, norender, props: submitButtonProps = {} } = getSubmitButtonOptions(uiSchema);
+ if (norender) {
+ return null;
+ }
+ return ;
+}
diff --git a/packages/primereact/src/SubmitButton/index.ts b/packages/primereact/src/SubmitButton/index.ts
new file mode 100644
index 0000000000..f676497ba2
--- /dev/null
+++ b/packages/primereact/src/SubmitButton/index.ts
@@ -0,0 +1,2 @@
+export { default } from './SubmitButton';
+export * from './SubmitButton';
diff --git a/packages/primereact/src/Templates/Templates.ts b/packages/primereact/src/Templates/Templates.ts
new file mode 100644
index 0000000000..94460602c7
--- /dev/null
+++ b/packages/primereact/src/Templates/Templates.ts
@@ -0,0 +1,50 @@
+import { FormContextType, RJSFSchema, StrictRJSFSchema, TemplatesType } from '@rjsf/utils';
+
+import AddButton from '../AddButton';
+import ArrayFieldItemTemplate from '../ArrayFieldItemTemplate';
+import ArrayFieldTemplate from '../ArrayFieldTemplate';
+import BaseInputTemplate from '../BaseInputTemplate';
+import DescriptionField from '../DescriptionField';
+import ErrorList from '../ErrorList';
+import { CopyButton, MoveDownButton, MoveUpButton, RemoveButton } from '../IconButton';
+import FieldErrorTemplate from '../FieldErrorTemplate';
+import FieldHelpTemplate from '../FieldHelpTemplate';
+import FieldTemplate from '../FieldTemplate';
+import ObjectFieldTemplate from '../ObjectFieldTemplate';
+import SubmitButton from '../SubmitButton';
+import TitleField from '../TitleField';
+import WrapIfAdditionalTemplate from '../WrapIfAdditionalTemplate';
+import ArrayFieldTitleTemplate from '../ArrayFieldTitleTemplate';
+import GridTemplate from '../GridTemplate';
+
+export function generateTemplates<
+ T = any,
+ S extends StrictRJSFSchema = RJSFSchema,
+ F extends FormContextType = any,
+>(): Partial> {
+ return {
+ ArrayFieldItemTemplate,
+ ArrayFieldTemplate,
+ ArrayFieldTitleTemplate,
+ BaseInputTemplate,
+ ButtonTemplates: {
+ AddButton,
+ CopyButton,
+ MoveDownButton,
+ MoveUpButton,
+ RemoveButton,
+ SubmitButton,
+ },
+ DescriptionFieldTemplate: DescriptionField,
+ ErrorListTemplate: ErrorList,
+ FieldErrorTemplate,
+ FieldHelpTemplate,
+ FieldTemplate,
+ ObjectFieldTemplate,
+ TitleFieldTemplate: TitleField,
+ WrapIfAdditionalTemplate,
+ GridTemplate,
+ };
+}
+
+export default generateTemplates();
diff --git a/packages/primereact/src/Templates/index.ts b/packages/primereact/src/Templates/index.ts
new file mode 100644
index 0000000000..612ccf692a
--- /dev/null
+++ b/packages/primereact/src/Templates/index.ts
@@ -0,0 +1,2 @@
+export { default } from './Templates';
+export * from './Templates';
diff --git a/packages/primereact/src/TextareaWidget/TextareaWidget.tsx b/packages/primereact/src/TextareaWidget/TextareaWidget.tsx
new file mode 100644
index 0000000000..bb4b0586e3
--- /dev/null
+++ b/packages/primereact/src/TextareaWidget/TextareaWidget.tsx
@@ -0,0 +1,41 @@
+import { ChangeEvent } from 'react';
+import { InputTextarea } from 'primereact/inputtextarea';
+import { FormContextType, RJSFSchema, StrictRJSFSchema, WidgetProps } from '@rjsf/utils';
+
+/** The `TextareaWidget` is a widget for rendering input fields as textarea using PrimeReact.
+ *
+ * @param props - The `WidgetProps` for this component
+ */
+export default function TextareaWidget<
+ T = any,
+ S extends StrictRJSFSchema = RJSFSchema,
+ F extends FormContextType = any,
+>(props: WidgetProps) {
+ const { id, value, required, disabled, readonly, autofocus, onChange, onBlur, onFocus, options } = props;
+ const primeProps = (options.prime || {}) as object;
+
+ let rows = 5;
+ // noinspection SuspiciousTypeOfGuard
+ if (typeof options.rows === 'string' || typeof options.rows === 'number') {
+ rows = Number(options.rows);
+ }
+
+ const handleChange = (event: ChangeEvent) => {
+ onChange(event.target.value === '' ? options.emptyValue : event.target.value);
+ };
+
+ return (
+ onBlur(id, event.target.value))}
+ onFocus={onFocus && ((event) => onFocus(id, event.target.value))}
+ />
+ );
+}
diff --git a/packages/primereact/src/TextareaWidget/index.ts b/packages/primereact/src/TextareaWidget/index.ts
new file mode 100644
index 0000000000..20e6d8e26b
--- /dev/null
+++ b/packages/primereact/src/TextareaWidget/index.ts
@@ -0,0 +1,2 @@
+export { default } from './TextareaWidget';
+export * from './TextareaWidget';
diff --git a/packages/primereact/src/Theme/Theme.ts b/packages/primereact/src/Theme/Theme.ts
new file mode 100644
index 0000000000..ed0ac9fd45
--- /dev/null
+++ b/packages/primereact/src/Theme/Theme.ts
@@ -0,0 +1,18 @@
+import { FormContextType, RJSFSchema, StrictRJSFSchema } from '@rjsf/utils';
+import { ThemeProps } from '@rjsf/core';
+
+import { generateTemplates } from '../Templates';
+import { generateWidgets } from '../Widgets';
+
+export function generateTheme<
+ T = any,
+ S extends StrictRJSFSchema = RJSFSchema,
+ F extends FormContextType = any,
+>(): ThemeProps {
+ return {
+ templates: generateTemplates(),
+ widgets: generateWidgets(),
+ };
+}
+
+export default generateTheme();
diff --git a/packages/primereact/src/Theme/index.ts b/packages/primereact/src/Theme/index.ts
new file mode 100644
index 0000000000..6dfd7fa6e1
--- /dev/null
+++ b/packages/primereact/src/Theme/index.ts
@@ -0,0 +1,2 @@
+export { default } from './Theme';
+export * from './Theme';
diff --git a/packages/primereact/src/TitleField/TitleField.tsx b/packages/primereact/src/TitleField/TitleField.tsx
new file mode 100644
index 0000000000..fc7d1496a7
--- /dev/null
+++ b/packages/primereact/src/TitleField/TitleField.tsx
@@ -0,0 +1,23 @@
+import { Divider } from 'primereact/divider';
+import { FormContextType, getUiOptions, RJSFSchema, StrictRJSFSchema, TitleFieldProps, titleId } from '@rjsf/utils';
+
+/** The `TitleField` is the template to use to render the title of a field
+ *
+ * @param props - The `TitleFieldProps` for this component
+ */
+export default function TitleField({
+ id,
+ title,
+ uiSchema,
+ required,
+}: TitleFieldProps) {
+ const uiOptions = getUiOptions(uiSchema);
+ return (
+
+
('root') ? '1.5rem' : '1.2rem' }}>
+ {uiOptions.title || title} {required ? '*' : ''}
+
+
+
+ );
+}
diff --git a/packages/primereact/src/TitleField/index.ts b/packages/primereact/src/TitleField/index.ts
new file mode 100644
index 0000000000..cfa479d034
--- /dev/null
+++ b/packages/primereact/src/TitleField/index.ts
@@ -0,0 +1,2 @@
+export { default } from './TitleField';
+export * from './TitleField';
diff --git a/packages/primereact/src/UpDownWidget/UpDownWidget.tsx b/packages/primereact/src/UpDownWidget/UpDownWidget.tsx
new file mode 100644
index 0000000000..15eed6c257
--- /dev/null
+++ b/packages/primereact/src/UpDownWidget/UpDownWidget.tsx
@@ -0,0 +1,70 @@
+import {
+ ariaDescribedByIds,
+ FormContextType,
+ getInputProps,
+ RJSFSchema,
+ StrictRJSFSchema,
+ WidgetProps,
+} from '@rjsf/utils';
+import { InputNumber, InputNumberChangeEvent } from 'primereact/inputnumber';
+
+/** The `UpDownWidget` renders an input component for a number.
+ *
+ * @param props - The `WidgetProps` for this component
+ */
+export default function UpDownWidget(
+ props: WidgetProps,
+) {
+ const {
+ id,
+ placeholder,
+ value,
+ required,
+ readonly,
+ disabled,
+ onChange,
+ onChangeOverride,
+ onBlur,
+ onFocus,
+ autofocus,
+ options,
+ schema,
+ type,
+ rawErrors = [],
+ } = props;
+ const inputProps = getInputProps(schema, type, options);
+ const { showButtons, buttonLayout, useGrouping, minFractionDigits, maxFractionDigits, locale, currency } = options;
+ const primeProps = (options.prime || {}) as object;
+
+ const _onChange = (event: InputNumberChangeEvent) => onChange(event.value === null ? options.emptyValue : value);
+ const _onBlur = () => onBlur && onBlur(id, value);
+ const _onFocus = () => onFocus && onFocus(id, value);
+
+ return (
+ 0}
+ onChange={(onChangeOverride as any) || _onChange}
+ onBlur={_onBlur}
+ onFocus={_onFocus}
+ aria-describedby={ariaDescribedByIds(id, !!schema.examples)}
+ />
+ );
+}
diff --git a/packages/primereact/src/UpDownWidget/index.ts b/packages/primereact/src/UpDownWidget/index.ts
new file mode 100644
index 0000000000..2e2ae55279
--- /dev/null
+++ b/packages/primereact/src/UpDownWidget/index.ts
@@ -0,0 +1,2 @@
+export { default } from './UpDownWidget';
+export * from './UpDownWidget';
diff --git a/packages/primereact/src/Widgets/Widgets.tsx b/packages/primereact/src/Widgets/Widgets.tsx
new file mode 100644
index 0000000000..82ab20c696
--- /dev/null
+++ b/packages/primereact/src/Widgets/Widgets.tsx
@@ -0,0 +1,33 @@
+import { FormContextType, RegistryWidgetsType, RJSFSchema, StrictRJSFSchema } from '@rjsf/utils';
+
+import AutoCompleteWidget from '../AutoCompleteWidget/AutoCompleteWidget';
+import CheckboxWidget from '../CheckboxWidget/CheckboxWidget';
+import CheckboxesWidget from '../CheckboxesWidget/CheckboxesWidget';
+import ColorWidget from '../ColorWidget/ColorWidget';
+import PasswordWidget from '../PasswordWidget/PasswordWidget';
+import RadioWidget from '../RadioWidget/RadioWidget';
+import RangeWidget from '../RangeWidget/RangeWidget';
+import SelectWidget from '../SelectWidget/SelectWidget';
+import TextareaWidget from '../TextareaWidget/TextareaWidget';
+import UpDownWidget from '../UpDownWidget/UpDownWidget';
+
+export function generateWidgets<
+ T = any,
+ S extends StrictRJSFSchema = RJSFSchema,
+ F extends FormContextType = any,
+>(): RegistryWidgetsType {
+ return {
+ AutoCompleteWidget,
+ CheckboxWidget,
+ CheckboxesWidget,
+ ColorWidget,
+ PasswordWidget,
+ RadioWidget,
+ RangeWidget,
+ SelectWidget,
+ TextareaWidget,
+ UpDownWidget,
+ };
+}
+
+export default generateWidgets();
diff --git a/packages/primereact/src/Widgets/index.ts b/packages/primereact/src/Widgets/index.ts
new file mode 100644
index 0000000000..de857bf557
--- /dev/null
+++ b/packages/primereact/src/Widgets/index.ts
@@ -0,0 +1,2 @@
+export { default } from './Widgets';
+export * from './Widgets';
diff --git a/packages/primereact/src/WrapIfAdditionalTemplate/WrapIfAdditionalTemplate.tsx b/packages/primereact/src/WrapIfAdditionalTemplate/WrapIfAdditionalTemplate.tsx
new file mode 100644
index 0000000000..51629f82e2
--- /dev/null
+++ b/packages/primereact/src/WrapIfAdditionalTemplate/WrapIfAdditionalTemplate.tsx
@@ -0,0 +1,83 @@
+import { FocusEvent } from 'react';
+import {
+ ADDITIONAL_PROPERTY_FLAG,
+ buttonId,
+ FormContextType,
+ RJSFSchema,
+ StrictRJSFSchema,
+ TranslatableString,
+ WrapIfAdditionalTemplateProps,
+} from '@rjsf/utils';
+import { InputText } from 'primereact/inputtext';
+
+/** The `WrapIfAdditional` component is used by the `FieldTemplate` to rename, or remove properties that are
+ * part of an `additionalProperties` part of a schema.
+ *
+ * @param props - The `WrapIfAdditionalProps` for this component
+ */
+export default function WrapIfAdditionalTemplate<
+ T = any,
+ S extends StrictRJSFSchema = RJSFSchema,
+ F extends FormContextType = any,
+>({
+ classNames,
+ style,
+ children,
+ disabled,
+ id,
+ label,
+ onDropPropertyClick,
+ onKeyChange,
+ readonly,
+ required,
+ schema,
+ registry,
+}: WrapIfAdditionalTemplateProps) {
+ const { templates, translateString } = registry;
+ const { RemoveButton } = templates.ButtonTemplates;
+ const keyLabel = translateString(TranslatableString.KeyLabel, [label]);
+ const additional = ADDITIONAL_PROPERTY_FLAG in schema;
+
+ if (!additional) {
+ return (
+
+ {children}
+
+ );
+ }
+
+ const handleBlur = ({ target }: FocusEvent) => onKeyChange(target.value);
+
+ return (
+
+
+
+
+
+
{children}
+
+ (id, 'remove')}
+ className='rjsf-object-property-remove'
+ disabled={disabled || readonly}
+ onClick={onDropPropertyClick(label)}
+ registry={registry}
+ />
+
+
+ );
+}
diff --git a/packages/primereact/src/WrapIfAdditionalTemplate/index.ts b/packages/primereact/src/WrapIfAdditionalTemplate/index.ts
new file mode 100644
index 0000000000..7d7af6629d
--- /dev/null
+++ b/packages/primereact/src/WrapIfAdditionalTemplate/index.ts
@@ -0,0 +1,2 @@
+export { default } from './WrapIfAdditionalTemplate';
+export * from './WrapIfAdditionalTemplate';
diff --git a/packages/primereact/src/index.ts b/packages/primereact/src/index.ts
new file mode 100644
index 0000000000..88529b8164
--- /dev/null
+++ b/packages/primereact/src/index.ts
@@ -0,0 +1,8 @@
+import PrimeForm from './PrimeForm/PrimeForm';
+
+export { default as Templates, generateTemplates } from './Templates';
+export { default as Form, generateForm } from './PrimeForm';
+export { default as Theme, generateTheme } from './Theme';
+export { default as Widgets, generateWidgets } from './Widgets';
+
+export default PrimeForm;
diff --git a/packages/primereact/src/tsconfig.json b/packages/primereact/src/tsconfig.json
new file mode 100644
index 0000000000..9ee9350a16
--- /dev/null
+++ b/packages/primereact/src/tsconfig.json
@@ -0,0 +1,24 @@
+{
+ "extends": "../../../tsconfig.base.json",
+ "include": [
+ "./"
+ ],
+ "compilerOptions": {
+ "rootDir": "./",
+ "outDir": "../lib",
+ "baseUrl": "../",
+ "jsx": "react-jsx",
+ "skipLibCheck": true
+ },
+ "references": [
+ {
+ "path": "../../core"
+ },
+ {
+ "path": "../../utils"
+ },
+ {
+ "path": "../../validator-ajv8"
+ }
+ ]
+}
diff --git a/packages/primereact/src/util.tsx b/packages/primereact/src/util.tsx
new file mode 100644
index 0000000000..b73820a291
--- /dev/null
+++ b/packages/primereact/src/util.tsx
@@ -0,0 +1,11 @@
+export function Label({ id, text, required }: { id: string; text?: string; required?: boolean }) {
+ if (!text) {
+ return null;
+ }
+
+ return (
+
+ );
+}
diff --git a/packages/primereact/test/Array.test.tsx b/packages/primereact/test/Array.test.tsx
new file mode 100644
index 0000000000..a21a3c150b
--- /dev/null
+++ b/packages/primereact/test/Array.test.tsx
@@ -0,0 +1,18 @@
+import { arrayTests } from '@rjsf/snapshot-tests';
+
+import Form from '../src';
+
+// Mock PrimeReact components that use parentElement or real DOM
+jest.mock('primereact/dropdown', () => ({
+ Dropdown: (props: Record) => ,
+}));
+
+jest.mock('primereact/multiselect', () => ({
+ MultiSelect: (props: Record) => ,
+}));
+
+jest.mock('primereact/slider', () => ({
+ Slider: (props: Record) => ,
+}));
+
+arrayTests(Form);
diff --git a/packages/primereact/test/Form.test.tsx b/packages/primereact/test/Form.test.tsx
new file mode 100644
index 0000000000..ced687688f
--- /dev/null
+++ b/packages/primereact/test/Form.test.tsx
@@ -0,0 +1,18 @@
+import { formTests } from '@rjsf/snapshot-tests';
+
+import Form from '../src';
+
+// Mock PrimeReact components that use parentElement or real DOM
+jest.mock('primereact/dropdown', () => ({
+ Dropdown: (props: Record) => ,
+}));
+
+jest.mock('primereact/multiselect', () => ({
+ MultiSelect: (props: Record) => ,
+}));
+
+jest.mock('primereact/slider', () => ({
+ Slider: (props: Record) => ,
+}));
+
+formTests(Form);
diff --git a/packages/primereact/test/GridSnap.test.tsx b/packages/primereact/test/GridSnap.test.tsx
new file mode 100644
index 0000000000..00f556c56c
--- /dev/null
+++ b/packages/primereact/test/GridSnap.test.tsx
@@ -0,0 +1,185 @@
+import { gridTests } from '@rjsf/snapshot-tests';
+
+import Form from '../src';
+
+// Mock PrimeReact components that use parentElement or real DOM
+jest.mock('primereact/dropdown', () => ({
+ Dropdown: (props: Record) => ,
+}));
+
+jest.mock('primereact/multiselect', () => ({
+ MultiSelect: (props: Record) => ,
+}));
+
+jest.mock('primereact/slider', () => ({
+ Slider: (props: Record) => ,
+}));
+
+gridTests(Form, {
+ ColumnWidthAll: { xs: 12 },
+ ColumnWidth4: { xs: 4 },
+ ColumnWidth6: { xs: 6 },
+ ColumnWidth8: { xs: 8 },
+ Row2Columns: {},
+ Row3Columns: {},
+ ComplexUiSchema: {
+ 'ui:field': 'LayoutGridField',
+ 'ui:layoutGrid': {
+ 'ui:row': {
+ children: [
+ {
+ 'ui:col': {
+ children: ['person'],
+ },
+ },
+ {
+ 'ui:columns': {
+ xs: 4,
+ children: ['person.name.first', 'person.name.middle', 'person.name.last'],
+ },
+ },
+ {
+ 'ui:col': {
+ sm: 4,
+ children: ['person.birth_date'],
+ },
+ },
+ {
+ 'ui:col': {
+ sm: 8,
+ children: ['person.race'],
+ },
+ },
+ {
+ 'ui:col': {
+ sm: 6,
+ children: [
+ {
+ 'ui:row': {
+ children: [
+ {
+ 'ui:columns': {
+ children: ['person.address.line_1', 'person.address.line_2', 'person.address.city'],
+ },
+ },
+ {
+ 'ui:columns': {
+ sm: 6,
+ children: ['person.address.state', 'person.address.postal_code'],
+ },
+ },
+ ],
+ },
+ },
+ ],
+ },
+ },
+ {
+ 'ui:col': {
+ sm: 6,
+ children: [
+ {
+ 'ui:row': {
+ children: [
+ {
+ 'ui:columns': {
+ children: ['employment'],
+ },
+ },
+ {
+ 'ui:condition': {
+ field: 'employment.job_type',
+ value: 'company',
+ operator: 'all',
+ children: [
+ {
+ 'ui:columns': {
+ children: ['employment.business', 'employment.title'],
+ },
+ },
+ {
+ 'ui:col': {
+ children: ['employment.location.city'],
+ },
+ },
+ {
+ 'ui:col': {
+ children: ['employment.location.state'],
+ },
+ },
+ ],
+ },
+ },
+ {
+ 'ui:condition': {
+ field: 'employment.job_type',
+ value: 'education',
+ operator: 'all',
+ children: [
+ {
+ 'ui:columns': {
+ children: ['employment.district', 'employment.school', 'employment.title'],
+ },
+ },
+ {
+ 'ui:col': {
+ children: ['employment.location.city'],
+ },
+ },
+ {
+ 'ui:col': {
+ children: ['employment.location.state'],
+ },
+ },
+ ],
+ },
+ },
+ {
+ 'ui:condition': {
+ field: 'employment.job_type',
+ value: 'other',
+ operator: 'all',
+ children: [
+ {
+ 'ui:columns': {
+ children: [
+ {
+ name: 'employment.description',
+ rows: 6,
+ },
+ ],
+ },
+ },
+ ],
+ },
+ },
+ ],
+ },
+ },
+ ],
+ },
+ },
+ ],
+ },
+ },
+ person: {
+ 'ui:field': 'LayoutHeaderField',
+ race: {
+ 'ui:options': {
+ widget: 'checkboxes',
+ },
+ },
+ address: {
+ 'ui:field': 'LayoutGridField',
+ },
+ },
+ employment: {
+ 'ui:options': {
+ inline: true,
+ },
+ description: {
+ 'ui:widget': 'textarea',
+ },
+ },
+ },
+});
diff --git a/packages/primereact/test/Object.test.tsx b/packages/primereact/test/Object.test.tsx
new file mode 100644
index 0000000000..dabe023e32
--- /dev/null
+++ b/packages/primereact/test/Object.test.tsx
@@ -0,0 +1,5 @@
+import { objectTests } from '@rjsf/snapshot-tests';
+
+import Form from '../src';
+
+objectTests(Form);
diff --git a/packages/primereact/test/__snapshots__/Array.test.tsx.snap b/packages/primereact/test/__snapshots__/Array.test.tsx.snap
new file mode 100644
index 0000000000..7f9ea00b51
--- /dev/null
+++ b/packages/primereact/test/__snapshots__/Array.test.tsx.snap
@@ -0,0 +1,4558 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`array fields array 1`] = `
+
+`;
+
+exports[`array fields array icons 1`] = `
+
+`;
+
+exports[`array fields checkboxes 1`] = `
+
+`;
+
+exports[`array fields empty errors array 1`] = `
+
+`;
+
+exports[`array fields fixed array 1`] = `
+
+`;
+
+exports[`array fields has errors 1`] = `
+
+`;
+
+exports[`array fields no errors 1`] = `
+
+`;
+
+exports[`with title and description array 1`] = `
+
+`;
+
+exports[`with title and description array icons 1`] = `
+
+`;
+
+exports[`with title and description checkboxes 1`] = `
+
+`;
+
+exports[`with title and description fixed array 1`] = `
+
+`;
+
+exports[`with title and description from both array 1`] = `
+
+`;
+
+exports[`with title and description from both array icons 1`] = `
+
+`;
+
+exports[`with title and description from both checkboxes 1`] = `
+
+`;
+
+exports[`with title and description from both fixed array 1`] = `
+
+`;
+
+exports[`with title and description from uiSchema array 1`] = `
+
+`;
+
+exports[`with title and description from uiSchema array icons 1`] = `
+
+`;
+
+exports[`with title and description from uiSchema checkboxes 1`] = `
+
+`;
+
+exports[`with title and description from uiSchema fixed array 1`] = `
+
+`;
+
+exports[`with title and description with global label off array 1`] = `
+
+`;
+
+exports[`with title and description with global label off array icons 1`] = `
+
+`;
+
+exports[`with title and description with global label off checkboxes 1`] = `
+
+`;
+
+exports[`with title and description with global label off fixed array 1`] = `
+
+`;
diff --git a/packages/primereact/test/__snapshots__/Form.test.tsx.snap b/packages/primereact/test/__snapshots__/Form.test.tsx.snap
new file mode 100644
index 0000000000..5e9c48660f
--- /dev/null
+++ b/packages/primereact/test/__snapshots__/Form.test.tsx.snap
@@ -0,0 +1,4144 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`single fields checkbox field 1`] = `
+
+`;
+
+exports[`single fields checkbox field with label 1`] = `
+
+`;
+
+exports[`single fields checkbox field with label and description 1`] = `
+
+`;
+
+exports[`single fields checkbox field with label and rich text description 1`] = `
+
+`;
+
+exports[`single fields checkboxes field 1`] = `
+
+`;
+
+exports[`single fields field with description 1`] = `
+
+`;
+
+exports[`single fields field with description in uiSchema 1`] = `
+
+`;
+
+exports[`single fields field with markdown description 1`] = `
+
+`;
+
+exports[`single fields field with markdown description in uiSchema 1`] = `
+
+`;
+
+exports[`single fields format color 1`] = `
+
+`;
+
+exports[`single fields format date 1`] = `
+
+`;
+
+exports[`single fields format datetime 1`] = `
+
+`;
+
+exports[`single fields format time 1`] = `
+
+`;
+
+exports[`single fields help and error display 1`] = `
+
+`;
+
+exports[`single fields hidden field 1`] = `
+
+`;
+
+exports[`single fields hidden label 1`] = `
+
+`;
+
+exports[`single fields null field 1`] = `
+
+`;
+
+exports[`single fields number field 0 1`] = `
+
+`;
+
+exports[`single fields number field 1`] = `
+
+`;
+
+exports[`single fields password field 1`] = `
+
+`;
+
+exports[`single fields radio field 1`] = `
+
+`;
+
+exports[`single fields schema examples 1`] = `
+
+`;
+
+exports[`single fields select field 1`] = `
+
+`;
+
+exports[`single fields select field multiple choice 1`] = `
+
+`;
+
+exports[`single fields select field multiple choice enumDisabled 1`] = `
+
+`;
+
+exports[`single fields select field multiple choice enumDisabled using checkboxes 1`] = `
+
+`;
+
+exports[`single fields select field multiple choice formData 1`] = `
+
+`;
+
+exports[`single fields select field multiple choice with labels 1`] = `
+
+`;
+
+exports[`single fields select field single choice enumDisabled 1`] = `
+
+`;
+
+exports[`single fields select field single choice enumDisabled using radio widget 1`] = `
+
+`;
+
+exports[`single fields select field single choice form disabled using radio widget 1`] = `
+
+`;
+
+exports[`single fields select field single choice formData 1`] = `
+
+`;
+
+exports[`single fields select field single choice uiSchema disabled using radio widget 1`] = `
+
+`;
+
+exports[`single fields slider field 1`] = `
+
+`;
+
+exports[`single fields string field format data-url 1`] = `
+
+`;
+
+exports[`single fields string field format email 1`] = `
+
+`;
+
+exports[`single fields string field format uri 1`] = `
+
+`;
+
+exports[`single fields string field regular 1`] = `
+
+`;
+
+exports[`single fields string field with placeholder 1`] = `
+
+`;
+
+exports[`single fields textarea field 1`] = `
+
+`;
+
+exports[`single fields title field 1`] = `
+
+`;
+
+exports[`single fields unsupported field 1`] = `
+
+`;
+
+exports[`single fields up/down field 1`] = `
+
+`;
+
+exports[`single fields using custom tagName 1`] = `
+
+`;
diff --git a/packages/primereact/test/__snapshots__/GridSnap.test.tsx.snap b/packages/primereact/test/__snapshots__/GridSnap.test.tsx.snap
new file mode 100644
index 0000000000..3520710dcc
--- /dev/null
+++ b/packages/primereact/test/__snapshots__/GridSnap.test.tsx.snap
@@ -0,0 +1,9408 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Complex grid renders person and address and employment in a complex grid, job_type = company 1`] = `
+
+`;
+
+exports[`Complex grid renders person and address and employment in a complex grid, job_type = education 1`] = `
+
+`;
+
+exports[`Complex grid renders person and address and employment in a complex grid, job_type = other 1`] = `
+
+`;
+
+exports[`Complex grid renders person and address and employment in a complex grid, no form data 1`] = `
+
+`;
+
+exports[`Three even column grid renders person and address in three columns, no employment 1`] = `
+
+`;
+
+exports[`Two even column grid renders person and address in two columns, no employment 1`] = `
+
+`;
diff --git a/packages/primereact/test/__snapshots__/Object.test.tsx.snap b/packages/primereact/test/__snapshots__/Object.test.tsx.snap
new file mode 100644
index 0000000000..3aacabf663
--- /dev/null
+++ b/packages/primereact/test/__snapshots__/Object.test.tsx.snap
@@ -0,0 +1,2716 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`object fields additionalProperties 1`] = `
+
+`;
+
+exports[`object fields object 1`] = `
+
+`;
+
+exports[`object fields show add button and fields if additionalProperties is true and not an object 1`] = `
+
+`;
+
+exports[`object fields with title and description additionalProperties 1`] = `
+
+`;
+
+exports[`object fields with title and description from both additionalProperties 1`] = `
+
+`;
+
+exports[`object fields with title and description from both object 1`] = `
+
+`;
+
+exports[`object fields with title and description from uiSchema additionalProperties 1`] = `
+
+`;
+
+exports[`object fields with title and description from uiSchema object 1`] = `
+
+`;
+
+exports[`object fields with title and description from uiSchema show add button and fields if additionalProperties is true and not an object 1`] = `
+
+`;
+
+exports[`object fields with title and description object 1`] = `
+
+`;
+
+exports[`object fields with title and description show add button and fields if additionalProperties is true and not an object 1`] = `
+
+`;
+
+exports[`object fields with title and description with global label off additionalProperties 1`] = `
+
+`;
+
+exports[`object fields with title and description with global label off object 1`] = `
+
+`;
+
+exports[`object fields with title and description with global label off show add button and fields if additionalProperties is true and not an object 1`] = `
+
+`;
diff --git a/packages/primereact/test/setup.ts b/packages/primereact/test/setup.ts
new file mode 100644
index 0000000000..96edf64211
--- /dev/null
+++ b/packages/primereact/test/setup.ts
@@ -0,0 +1,22 @@
+// Mock style injection
+const originalCreateElement = document.createElement.bind(document);
+
+beforeAll(() => {
+ document.createElement = (tagName: string) => {
+ const element = originalCreateElement(tagName);
+ if (tagName === 'style') {
+ Object.defineProperty(element, 'textContent', {
+ set() {
+ // Block style content
+ },
+ });
+ }
+ return element;
+ };
+});
+
+afterAll(() => {
+ document.createElement = originalCreateElement;
+});
+
+export {};
diff --git a/packages/primereact/test/tsconfig.json b/packages/primereact/test/tsconfig.json
new file mode 100644
index 0000000000..d97653648c
--- /dev/null
+++ b/packages/primereact/test/tsconfig.json
@@ -0,0 +1,20 @@
+{
+ "extends": "../../../tsconfig.base.json",
+ "include": [
+ "./"
+ ],
+ "compilerOptions": {
+ "rootDir": "./",
+ "baseUrl": "../",
+ "noEmit": true,
+ "jsx": "react-jsx"
+ },
+ "references": [
+ {
+ "path": "../src"
+ },
+ {
+ "path": "../../snapshot-tests"
+ }
+ ]
+}
diff --git a/packages/primereact/tsconfig.build.json b/packages/primereact/tsconfig.build.json
new file mode 100644
index 0000000000..827cfe1018
--- /dev/null
+++ b/packages/primereact/tsconfig.build.json
@@ -0,0 +1,16 @@
+{
+ "extends": "../../tsconfig.build.json",
+ "compilerOptions": {
+ "outDir": "./lib"
+ },
+ "files": [],
+ "references": [
+ {
+ "path": "./src"
+ }
+ ],
+ "tsc-alias": {
+ "resolveFullPaths": true,
+ "verbose": true,
+ }
+}
diff --git a/packages/primereact/tsconfig.json b/packages/primereact/tsconfig.json
new file mode 100644
index 0000000000..82462dfbeb
--- /dev/null
+++ b/packages/primereact/tsconfig.json
@@ -0,0 +1,12 @@
+{
+ "extends": "../../tsconfig.base.json",
+ "files": [],
+ "references": [
+ {
+ "path": "./src"
+ },
+ {
+ "path": "./test"
+ }
+ ]
+}