Skip to content

DaisyUI v5 Theme for React JSON Schema Form v6 #4551

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Apr 17, 2025
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
- [Bootstrap 3](https://github.com/rjsf-team/react-jsonschema-form/tree/main/packages/core)
- [React-Bootstrap (Bootstrap 5)](https://github.com/rjsf-team/react-jsonschema-form/tree/main/packages/react-bootstrap)
- [Chakra UI](https://github.com/rjsf-team/react-jsonschema-form/tree/main/packages/chakra-ui)
- [Daisy UI](https://github.com/rjsf-team/react-jsonschema-form/tree/main/packages/daisyui)
- [Fluent UI 9](https://github.com/rjsf-team/react-jsonschema-form/tree/main/packages/fluentui-rc)
- [Material UI 5](https://github.com/rjsf-team/react-jsonschema-form/tree/main/packages/mui)
- [Semantic UI](https://github.com/rjsf-team/react-jsonschema-form/tree/main/packages/semantic-ui)
Expand Down
11,197 changes: 7,275 additions & 3,922 deletions package-lock.json

Large diffs are not rendered by default.

8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
"packages/antd",
"packages/chakra-ui",
"packages/core",
"packages/daisyui",
"packages/docs",
"packages/fluentui-rc",
"packages/mui",
Expand All @@ -81,5 +82,10 @@
"packages/validator-ajv8",
"packages/snapshot-tests",
"packages/shadcn"
]
],
"dependencies": {
"@restart/hooks": "^0.6.2",
"@restart/ui": "^1.9.4",
"uncontrollable": "^9.0.0"
}
}
95 changes: 95 additions & 0 deletions packages/core/src/components/widgets/RatingWidget.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { ChangeEvent, FocusEvent } from 'react';
import { FormContextType, RJSFSchema, StrictRJSFSchema, WidgetProps } from '@rjsf/utils';

/** The `RatingWidget` component renders a star or heart rating input
*
* Features:
* - Configurable number of stars/hearts (1-5) with default of 5
* - Supports different shapes (star, heart)
* - Supports minimum and maximum values from schema
* - Handles required, disabled, and readonly states
* - Provides focus and blur event handling for accessibility
* - Uses radio inputs for a11y compatibility
*
* @param props - The `WidgetProps` for this component
*/
export default function RatingWidget<
T = any,
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>({
id,
value,
required,
disabled,
readonly,
autofocus,
onChange,
onFocus,
onBlur,
schema,
options,
}: WidgetProps<T, S, F>) {
const { stars = 5, shape = 'star' } = options;

// Use schema.maximum if provided, otherwise use stars option (limited to 1-5)
const numStars = schema.maximum ? Math.min(schema.maximum, 5) : Math.min(Math.max(stars as number, 1), 5);
const min = schema.minimum || 0;

/** Handles change events from radio inputs
*
* @param event - The change event
*/
const _onChange = ({ target: { value } }: ChangeEvent<HTMLInputElement>) => {
onChange(parseInt(value));
};

/** Handles focus events for accessibility
*
* @param event - The focus event
* @param starValue - The value of the focused star
*/
const handleFocus = (event: FocusEvent<HTMLInputElement>, starValue: number) => {
if (onFocus) {
onFocus(id, starValue);
}
};

/** Handles blur events for accessibility
*
* @param event - The blur event
* @param starValue - The value of the blurred star
*/
const handleBlur = (event: FocusEvent<HTMLInputElement>, starValue: number) => {
if (onBlur) {
onBlur(id, starValue);
}
};

return (
<div className='field field-array'>
<div className='rating'>
{[...Array(numStars)].map((_, index) => {
const starValue = min + index;
return (
<input
key={index}
type='radio'
name={id}
value={starValue}
checked={value === starValue}
onChange={_onChange}
onFocus={(e) => handleFocus(e, starValue)}
onBlur={(e) => handleBlur(e, starValue)}
className='rating-input'
disabled={disabled || readonly}
required={required}
autoFocus={autofocus && index === 0}
aria-label={`${starValue} ${shape === 'heart' ? 'heart' : 'star'}${starValue === 1 ? '' : 's'}`}
/>
);
})}
</div>
</div>
);
}
2 changes: 2 additions & 0 deletions packages/core/src/components/widgets/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import HiddenWidget from './HiddenWidget';
import PasswordWidget from './PasswordWidget';
import RadioWidget from './RadioWidget';
import RangeWidget from './RangeWidget';
import RatingWidget from './RatingWidget';
import SelectWidget from './SelectWidget';
import TextareaWidget from './TextareaWidget';
import TextWidget from './TextWidget';
Expand All @@ -39,6 +40,7 @@ function widgets<
PasswordWidget,
RadioWidget,
RangeWidget,
RatingWidget,
SelectWidget,
TextWidget,
TextareaWidget,
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import Form, { FormProps, FormState, IChangeEvent } from './components/Form';
import withTheme, { ThemeProps } from './withTheme';
import getDefaultRegistry from './getDefaultRegistry';
import RatingWidget from './components/widgets/RatingWidget';

export type { FormProps, FormState, IChangeEvent, ThemeProps };

export { withTheme, getDefaultRegistry };
export { withTheme, getDefaultRegistry, RatingWidget };
export default Form;
23 changes: 23 additions & 0 deletions packages/daisyui/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"extends": [
"../../.eslintrc"
],
"parser": "@typescript-eslint/parser",
"plugins": [
"@typescript-eslint",
"react"
],
"env": {
"browser": true,
"es2021": true
},
"settings": {
"react": {
"version": "detect"
}
},
"rules": {
"react/prop-types": "off",
"@typescript-eslint/explicit-module-boundary-types": "off"
}
}
209 changes: 209 additions & 0 deletions packages/daisyui/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
# @rjsf/daisyui

[![Build Status][build-shield]][build-url]
[![npm][npm-shield]][npm-url]
[![npm downloads][npm-dl-shield]][npm-dl-url]
[![Contributors][contributors-shield]][contributors-url]
[![License][license-shield]][license-url]

A [DaisyUI](https://daisyui.com/) theme for [react-jsonschema-form](https://github.com/rjsf-team/react-jsonschema-form/).

This package integrates DaisyUI v6, Tailwind CSS v4, and RJSF v6 to provide a modern, customizable form experience.

## Features

- Complete DaisyUI v6 styling for all RJSF form elements
- Responsive design with mobile-friendly layouts
- Connected card styling for nested elements and arrays
- Consistent visual hierarchy for complex forms
- Support for all RJSF field types including:
- Text inputs with proper styling and validation states
- Select dropdowns with customizable option rendering
- Checkboxes and radio buttons with optimized layouts
- Arrays with add/remove/reorder functionality
- Objects with proper nesting and visual hierarchy
- Date/time inputs with cross-browser compatibility
- Support for custom themes via DaisyUI's theme system
- Accessible form components following WAI-ARIA practices

## Installation

```bash
npm install @rjsf/daisyui @rjsf/core @rjsf/utils tailwindcss@^4.0.0 daisyui@^6.0.0
```

## Usage

```jsx
import { Form } from '@rjsf/daisyui';
import validator from '@rjsf/validator-ajv8';

function App() {
return (
<Form
schema={schema}
uiSchema={uiSchema}
validator={validator}
onChange={console.log}
onSubmit={console.log}
/>
);
}
```

## Theme Customization

The form components use DaisyUI's theme system. You can customize the theme by adding DaisyUI theme classes to your HTML:

```html
<html data-theme="light">
<!-- or any other DaisyUI theme -->
</html>
```

For dynamic theme switching, you can change the data-theme attribute in your application code.

## Tailwind Configuration

Make sure your `tailwind.config.js` includes the DaisyUI plugin:

```js
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./src/**/*.{js,jsx,ts,tsx}",
],
theme: {
extend: {},
},
plugins: [require("daisyui")],
daisyui: {
themes: true,
},
}
```

## Development

```bash
# Install dependencies
npm install

# Build the package
npm run build

# Run the development server
npm run dev
```

## Customization

### Grid Layout

The DaisyUI theme supports the standard RJSF layout grid system. You can use grid layouts by incorporating the `LayoutGridField` in your UI schema:

```jsx
import { RJSFSchema, UiSchema } from "@rjsf/utils";
import Form from "@rjsf/daisyui";
import validator from "@rjsf/validator-ajv8";

const schema = {
type: "object",
properties: {
firstName: { type: "string", title: "First Name" },
lastName: { type: "string", title: "Last Name" },
email: { type: "string", format: "email", title: "Email" },
phone: { type: "string", title: "Phone" }
}
};

// Use grid layout for the form
const uiSchema = {
"ui:field": "LayoutGridField",
"ui:layoutGrid": {
"ui:row": {
children: [
{
"ui:row": {
children: [
{
"ui:col": {
xs: 12,
sm: 6,
children: ["firstName"]
}
},
{
"ui:col": {
xs: 12,
sm: 6,
children: ["lastName"]
}
}
]
}
},
{
"ui:row": {
children: [
{
"ui:col": {
xs: 12,
sm: 6,
children: ["email"]
}
},
{
"ui:col": {
xs: 12,
sm: 6,
children: ["phone"]
}
}
]
}
}
]
}
}
};

const MyForm = () => (
<Form
schema={schema}
uiSchema={uiSchema}
validator={validator}
/>
);
```

The DaisyUI theme uses a flexible grid system based on Tailwind CSS's flex utilities. This grid layout integrates with the standard RJSF layout system, providing a consistent experience across all themes.

## Theme Configuration

DaisyUI itself provides a variety of themes. To use a specific theme, add the `data-theme` attribute to your root element or use the `ThemeProvider` component.

```jsx
import { ThemeProvider } from '@rjsf/daisyui';

const App = () => (
<ThemeProvider>
<Form schema={schema} validator={validator} />
</ThemeProvider>
);
```

## License

Apache-2.0

[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
[npm-shield]: https://img.shields.io/npm/v/@rjsf/daisyui/latest.svg?style=flat-square
[npm-url]: https://www.npmjs.com/package/@rjsf/daisyui
[npm-dl-shield]: https://img.shields.io/npm/dm/@rjsf/daisyui.svg?style=flat-square
[npm-dl-url]: https://www.npmjs.com/package/@rjsf/daisyui
[contributors-shield]: https://img.shields.io/github/contributors/rjsf-team/react-jsonschema-form.svg?style=flat-square
[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://github.com/rjsf-team/react-jsonschema-form/blob/main/LICENSE
4 changes: 4 additions & 0 deletions packages/daisyui/babel.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "../../babel.config.json"
}

Loading
Loading