Search code examples
reactjsreact-jsonschema-forms

Overriding BaseInput Widget in React JSON Schema Form v4


I'm working with React JSON Schema Form v4 and trying to override the BaseInput widget with a custom implementation. I've declared my default widgets like this:

const defaultWidgets: Widgets = {
  DateWidget: DatePickerWidget,
  DateTimeWidget: DatePickerWidget,
  FileWidget: FileWidget,
  BaseInput: BaseInput
};

However, when I render a form, the custom BaseInput widget doesn't seem to be applied. Here's a snippet of my SchemaForm component:

import { AjvError, withTheme, IChangeEvent, ErrorSchema, FormProps, ISubmitEvent, Widget } from '@rjsf/core';
import { Theme as AntDTheme } from '@rjsf/antd';
 
const Theme = { ...AntdTheme };

const ThemedForm = withTheme(Theme);

const SchemaForm = <T extends object>({
  // ... other props
  widgets = {},
  // ... other props
}: SchemaFormProps<T>) => {

  const formWidgets = { ...defaultWidgets, ...widgets };

  return (
    // ... rest of the component
    <ThemedForm
      // ... other props
      widgets={formWidgets}
      // ... other props
    >
      {children}
    </ThemedForm>
    // ... rest of the component
  );
};

I've tried different ways to declare and override the BaseInput widget, but it doesn't seem to work as expected. Can anyone guide me on the correct approach to override the BaseInput widget in React JSON Schema Form v4?

Also tried this approach, using uiSchema, but can't make it work.


Solution

  • When using react-declarative any input type can be overwritten with OneSlotFactory

    Link to the playground

    <OneSlotFactoryInternal Combo={ComboSlot} Date={DateSlot} Time={TimeSlot}>
      <App />
    </OneSlotFactoryInternal>
    
    ...
    
    import { DatePicker } from "@mui/x-date-pickers";
    import { useMemo } from "react";
    import { IDateSlot, datetime } from "react-declarative";
    import dayjs from "dayjs";
    
    export const DateSlot = ({
      invalid,
      value,
      disabled,
      description = "",
      outlined = true,
      title = "Text",
      labelShrink,
      dirty,
      autoFocus,
      inputRef,
      onChange,
      name,
    }: IDateSlot) => {
      const dayjsValue = useMemo(() => {
        if (value) {
          const date = datetime.parseDate(value);
          if (!date) {
            return undefined;
          }
          let now = dayjs();
          now = now.set("date", date.day);
          now = now.set("month", date.month - 1);
          now = now.set("year", date.year);
          return now;
        }
        return undefined;
      }, [value]);
    
      return (
        <DatePicker
          label={title}
          value={dayjsValue}
          onChange={(value: dayjs.Dayjs | null) => {
            if (value) {
              const day = value.get("date");
              const month = value.get("month") + 1;
              const year = value.get("year");
              onChange(new datetime.Date(day, month, year).toString());
              return;
            }
            onChange(null);
          }}
          slotProps={{
            textField: {
              inputRef,
              InputLabelProps: labelShrink
                ? {
                    shrink: labelShrink,
                  }
                : undefined,
              disabled,
              focused: autoFocus,
              variant: outlined ? "outlined" : "standard",
              label: title,
              name,
              helperText: (dirty && invalid) || description,
              error: dirty && invalid !== null,
            },
          }}
        />
      );
    };
    
    export default DateSlot;
    
    

    screenshot