CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-rjsf--material-ui

Material UI theme integration for react-jsonschema-form providing dual v4/v5 compatibility with Material Design components, widgets, fields, and themes for JSON schema-based forms.

Pending
Overview
Eval results
Files

component-context.mddocs/

Component Context

React Context system for providing Material UI components to form elements, enabling version compatibility and dependency injection. The context system allows widgets and fields to access Material UI components without direct imports.

Capabilities

MuiComponentContext

React Context that provides Material UI components to all child widgets and fields.

/**
 * React Context for providing Material UI components to widgets and fields
 * Can hold either Material UI v4 or v5 component references
 */
declare const MuiComponentContext: React.Context<MaterialUIContextProps | Mui5ContextProps | null>;

Features:

  • Version-agnostic component access
  • Dependency injection for Material UI components
  • Null-safe context handling
  • Support for both v4 and v5 simultaneously

Usage:

  • Automatically provided by form wrappers
  • Accessed via useMuiComponent hook
  • Can be customized for testing or specialized use cases

useMuiComponent Hook

Hook for accessing Material UI components from the context within widgets and fields.

/**
 * Hook to access Material UI components from context
 * @returns MaterialUIContextProps | Mui5ContextProps
 * @throws Error if no context provider is found
 */
function useMuiComponent(): MaterialUIContextProps | Mui5ContextProps;

Features:

  • Type-safe component access
  • Runtime error checking
  • Version detection
  • Component availability validation

Usage:

import { useMuiComponent } from "@rjsf/material-ui";

function CustomWidget(props: WidgetProps) {
  const { TextField, Button } = useMuiComponent();
  
  return (
    <TextField
      value={props.value}
      onChange={(e) => props.onChange(e.target.value)}
    />
  );
}

Context Types

MaterialUIContextProps (v4)

Interface defining Material UI v4 component structure:

interface MaterialUIContextProps {
  Box: React.ComponentType<BoxProps>;
  Button: React.ComponentType<ButtonProps>;
  Checkbox: React.ComponentType<CheckboxProps>;
  Divider: React.ComponentType<DividerProps>;
  Grid: React.ComponentType<GridProps>;
  FormControl: React.ComponentType<FormControlProps>;
  FormControlLabel: React.ComponentType<FormControlLabelProps>;
  FormGroup: React.ComponentType<FormGroupProps>;
  FormHelperText: React.ComponentType<FormHelperTextProps>;
  FormLabel: React.ComponentType<FormLabelProps>;
  IconButton: React.ComponentType<IconButtonProps>;
  Input: React.ComponentType<InputProps>;
  InputLabel: React.ComponentType<InputLabelProps>;
  List: React.ComponentType<ListProps>;
  ListItem: React.ComponentType<ListItemProps>;
  ListItemIcon: React.ComponentType<ListItemIconProps>;
  ListItemText: React.ComponentType<ListItemTextProps>;
  MenuItem: React.ComponentType<MenuItemProps>;
  Paper: React.ComponentType<PaperProps>;
  Radio: React.ComponentType<RadioProps>;
  RadioGroup: React.ComponentType<RadioGroupProps>;
  Slider: React.ComponentType<SliderProps>;
  TextField: React.ComponentType<Omit<TextFieldProps, 'color' | 'variant'>>;
  Typography: React.ComponentType<TypographyProps>;
  AddIcon: React.ComponentType<SvgIconProps>;
  ArrowDownwardIcon: React.ComponentType<SvgIconProps>;
  ArrowUpwardIcon: React.ComponentType<SvgIconProps>;
  ErrorIcon: React.ComponentType<SvgIconProps>;
  RemoveIcon: React.ComponentType<SvgIconProps>;
}

Mui5ContextProps (v5)

Interface defining Material UI v5 component structure:

interface Mui5ContextProps {
  Box: React.ComponentType<BoxProps>;
  Button: React.ComponentType<ButtonProps>;
  Checkbox: React.ComponentType<CheckboxProps>;
  Divider: React.ComponentType<DividerProps>;
  Grid: React.ComponentType<GridProps>;
  FormControl: React.ComponentType<FormControlProps>;
  FormControlLabel: React.ComponentType<FormControlLabelProps>;
  FormGroup: React.ComponentType<FormGroupProps>;
  FormHelperText: React.ComponentType<FormHelperTextProps>;
  FormLabel: React.ComponentType<FormLabelProps>;
  IconButton: React.ComponentType<IconButtonProps>;
  Input: React.ComponentType<OutlinedInputProps>; // Different from v4
  InputLabel: React.ComponentType<InputLabelProps>;
  List: React.ComponentType<ListProps>;
  ListItem: React.ComponentType<ListItemProps>;
  ListItemIcon: React.ComponentType<ListItemIconProps>;
  ListItemText: React.ComponentType<ListItemTextProps>;
  MenuItem: React.ComponentType<MenuItemProps>;
  Paper: React.ComponentType<PaperProps>;
  Radio: React.ComponentType<RadioProps>;
  RadioGroup: React.ComponentType<RadioGroupProps>;
  Slider: React.ComponentType<SliderProps>;
  TextField: React.ComponentType<Omit<TextFieldProps, 'color' | 'variant'>>;
  Typography: React.ComponentType<TypographyProps>;
  AddIcon: React.ComponentType<SvgIconProps>;
  ArrowDownwardIcon: React.ComponentType<SvgIconProps>;
  ArrowUpwardIcon: React.ComponentType<SvgIconProps>;
  ErrorIcon: React.ComponentType<SvgIconProps>;
  RemoveIcon: React.ComponentType<SvgIconProps>;
}

Context Providers

MaterialUIContext (v4)

Context value object containing Material UI v4 component references:

/**
 * Object containing @material-ui/core v4 component references
 * Null if Material UI v4 dependencies are not available
 */
declare const MaterialUIContext: MaterialUIContextProps | null;

Mui5Context (v5)

Context value object containing Material UI v5 component references:

/**
 * Object containing @mui/material v5 component references
 * Null if Material UI v5 dependencies are not available
 */
declare const Mui5Context: Mui5ContextProps | null;

Usage Examples

Custom Widget with Context

import { useMuiComponent } from "@rjsf/material-ui";
import { WidgetProps } from "@rjsf/core";

const CustomTextWidget: React.FC<WidgetProps> = (props) => {
  const { TextField, FormControl, FormHelperText } = useMuiComponent();
  
  return (
    <FormControl fullWidth>
      <TextField
        id={props.id}
        label={props.label}
        value={props.value || ""}
        onChange={(event) => props.onChange(event.target.value)}
        onBlur={() => props.onBlur && props.onBlur(props.id, props.value)}
        onFocus={() => props.onFocus && props.onFocus(props.id, props.value)}
        disabled={props.disabled}
        readonly={props.readonly}
        required={props.required}
        error={props.rawErrors && props.rawErrors.length > 0}
      />
      {props.rawErrors && props.rawErrors.length > 0 && (
        <FormHelperText error>
          {props.rawErrors.join(", ")}
        </FormHelperText>
      )}
    </FormControl>
  );
};

Context-Aware Component

import { useMuiComponent } from "@rjsf/material-ui";

const VersionAwareComponent: React.FC = () => {
  const components = useMuiComponent();
  
  // Detect version by checking component differences
  const isV5 = 'Input' in components && 
    components.Input.toString().includes('OutlinedInput');
  
  return (
    <div>
      <p>Using Material UI {isV5 ? 'v5' : 'v4'}</p>
      <components.Button variant="contained">
        Click me
      </components.Button>
    </div>
  );
};

Custom Context Provider

import { MuiComponentContext } from "@rjsf/material-ui";
import * as MuiV5 from "@mui/material";
import * as MuiIcons from "@mui/icons-material";

const customContextValue: Mui5ContextProps = {
  ...MuiV5,
  AddIcon: MuiIcons.Add,
  ArrowDownwardIcon: MuiIcons.ArrowDownward,
  ArrowUpwardIcon: MuiIcons.ArrowUpward,
  ErrorIcon: MuiIcons.Error,
  RemoveIcon: MuiIcons.Remove,
};

function CustomContextProvider({ children }: { children: React.ReactNode }) {
  return (
    <MuiComponentContext.Provider value={customContextValue}>
      {children}
    </MuiComponentContext.Provider>
  );
}

Error Handling

import { useMuiComponent } from "@rjsf/material-ui";

const SafeWidget: React.FC<WidgetProps> = (props) => {
  try {
    const { TextField } = useMuiComponent();
    
    return (
      <TextField
        value={props.value}
        onChange={(e) => props.onChange(e.target.value)}
      />
    );
  } catch (error) {
    return (
      <div style={{ color: 'red' }}>
        Material UI components not available: {error.message}
      </div>
    );
  }
};

Testing with Mock Context

import { render } from "@testing-library/react";
import { MuiComponentContext } from "@rjsf/material-ui";

const mockContext: Partial<MaterialUIContextProps> = {
  TextField: ({ value, onChange }) => (
    <input value={value} onChange={(e) => onChange(e)} />
  ),
  Button: ({ children, onClick }) => (
    <button onClick={onClick}>{children}</button>
  ),
};

function renderWithMockContext(component: React.ReactElement) {
  return render(
    <MuiComponentContext.Provider value={mockContext as any}>
      {component}
    </MuiComponentContext.Provider>
  );
}

// Usage in tests
test("widget renders correctly", () => {
  const { getByRole } = renderWithMockContext(<CustomWidget {...props} />);
  expect(getByRole("textbox")).toBeInTheDocument();
});

Context Architecture

The context system provides several key benefits:

  1. Version Abstraction: Widgets don't need to know which Material UI version is being used
  2. Dependency Injection: Components are provided rather than imported directly
  3. Testing Support: Easy to mock components for unit testing
  4. Bundle Optimization: Only the required Material UI version is included in the bundle
  5. Runtime Detection: Graceful handling when dependencies are missing

Error States

The context system handles several error conditions:

  • Missing Dependencies: Shows warning when Material UI packages aren't installed
  • Version Conflicts: Detects and handles mixed v4/v5 installations
  • Context Unavailable: Throws descriptive error when useMuiComponent is called outside provider
  • Component Missing: Graceful degradation when specific components aren't available

The form wrappers automatically display user-friendly warnings when Material UI dependencies are not available, preventing runtime crashes and providing clear guidance for resolution.

Install with Tessl CLI

npx tessl i tessl/npm-rjsf--material-ui

docs

component-context.md

field-templates.md

fields.md

form-components.md

index.md

themes.md

widgets.md

tile.json