Skip to main content

Introducing Workflow Engine, try for FREE workflowengine.io.

Mantine Components

Mantine is a modern React component library with accessible, customizable components. It focuses on developer experience, theming, and responsive design. FormEngine includes Mantine components as an alternative to Material UI and React Suite in the component library.

Getting Started with Mantine Components

Installation

Mantine components are available in the @react-form-builder/components-mantine package:

npm install @react-form-builder/components-mantine

Peer dependencies (Mantine packages) must also be installed as required by your usage:

npm install @mantine/core @mantine/dates
# Optional: @mantine/dropzone @mantine/tiptap

Basic Mantine setup

Mantine styles must be imported manually. This is different from React Suite where the builder can use a style-loader helper withCssLoader to inject styles automatically.

Mantine setup (manual CSS imports)
import {builderView, view} from '@react-form-builder/components-mantine'
import {FormBuilder} from '@react-form-builder/designer'
import {FormViewer} from '@react-form-builder/core'

import '@mantine/core/styles.css'
import '@mantine/dates/styles.css'
// Optional packages:
// import '@mantine/dropzone/styles.css'
// import '@mantine/tiptap/styles.css'

const getForm = () => JSON.stringify({
form: {
key: 'Screen',
type: 'Screen',
children: []
}
})

export const MantineBuilderBasic = () => <FormBuilder view={builderView} getForm={getForm}/>
export const MantineViewerBasic = () => <FormViewer view={view} getForm={getForm}/>

For setup details, see Mantine Getting Started.

Basic styling and theming

Mantine default color palettes (gray, grape, blue and others) follow the Open Color scale in the default theme.

Result
Loading...
Show code
function App() {
const [mode, setMode] = useState('vibrant')
const previewRootRef = useRef(null)
const colorByMode = {vibrant: 'cyan', contrast: 'grape', extreme: 'orange'}

const themeMap = {
  vibrant: createTheme({
    fontFamily: 'Open Sans, sans-serif',
    primaryColor: 'cyan',
    defaultRadius: 'md'
  }),
  contrast: createTheme({
    fontFamily: 'Georgia, serif',
    primaryColor: 'grape',
    defaultRadius: 'xl'
  }),
  extreme: createTheme({
    primaryColor: 'orange',
    primaryShade: {light: 7, dark: 4},
    fontFamily: '"Impact", "Arial Black", sans-serif',
    defaultRadius: 'xs'
  })
}

const form = useMemo(() => ({
  form: {
    key: 'Screen',
    type: 'Screen',
    children: [
      {
        key: 'title',
        type: 'MtTitle',
        props: {
          order: {value: 3},
          color: {value: colorByMode[mode]},
          children: {value: 'Sign up'}
        }
      },
      {
        key: 'email',
        type: 'MtTextInput',
        props: {
          label: {value: 'Email'},
          placeholder: {value: 'you@example.com'}
        }
      },
      {
        key: 'age',
        type: 'MtSlider',
        props: {
          label: {value: 'Age'},
          color: {value: colorByMode[mode]},
          min: {value: 13},
          max: {value: 100},
          step: {value: 1}
        }
      },
      {
        key: 'terms',
        type: 'MtCheckbox',
        props: {
          label: {value: 'I agree to terms and privacy policy'},
          color: {value: colorByMode[mode]}
        }
      },
      {
        key: 'submit',
        type: 'MtButton',
        props: {
          children: {value: 'Create account'},
          color: {value: colorByMode[mode]},
          fullWidth: {value: true}
        }
      }
    ]
  }
}), [mode])

const getForm = useCallback(() => JSON.stringify(form), [form])

return (
  <div id='mantine-live-root-theme' ref={previewRootRef} style={{display: 'grid', gap: 12}}>
    <label>
      Theme preset:{' '}
      <select value={mode} onChange={(event) => setMode(event.target.value)}>
        <option value='vibrant'>vibrant</option>
        <option value='contrast'>contrast</option>
        <option value='extreme'>extreme</option>
      </select>
    </label>
    <MantineProvider
      theme={themeMap[mode]}
      cssVariablesSelector='#mantine-live-root-theme'
      getRootElement={() => previewRootRef.current ?? undefined}
      withGlobalClasses={false}
    >
      <FormViewer view={mantineView} getForm={getForm}/>
    </MantineProvider>
  </div>
)
}

render(<App />)

For theme and provider options, see:

Light and dark theme handling

In Mantine's color scheme model, MantineProvider is the central manager. It controls light/dark/auto behavior with defaultColorScheme, persists the selected value through the manager, and applies the resolved mode through the data-mantine-color-scheme attribute used by component styles.

Use defaultColorScheme, forceColorScheme, and colorSchemeManager on MantineProvider for app-wide behavior. For system preference awareness, use useColorScheme from @mantine/hooks.

Light and dark setup with persistence
import {localStorageColorSchemeManager, MantineProvider} from '@mantine/core'
import {view} from '@react-form-builder/components-mantine'
import {FormViewer} from '@react-form-builder/core'
import {useColorScheme} from '@mantine/hooks'

const colorSchemeManager = localStorageColorSchemeManager({
key: 'example-viewer-color-scheme'
})

const getForm = () => JSON.stringify({form: {key: 'Screen', type: 'Screen', children: []}})

export const AppWithColorScheme = () => {
const systemColorScheme = useColorScheme()

return (
<MantineProvider
colorSchemeManager={colorSchemeManager}
defaultColorScheme={systemColorScheme === 'dark' ? 'dark' : 'light'}
// Uncomment to force one mode:
// forceColorScheme='dark'
>
<FormViewer view={view} getForm={getForm}/>
</MantineProvider>
)
}

When you need immediate client-side color scheme detection (for non-SSR usage), pass getInitialValueInEffect: true:

import {useColorScheme} from '@mantine/hooks'

const colorScheme = useColorScheme('light', {getInitialValueInEffect: true})
Result
Loading...
Show code
function App() {
const [forceColorScheme, setForceColorScheme] = useState('none')
const colorSchemeManager = useMemo(
  () => localStorageColorSchemeManager({key: 'docs-mantine-scheme'}),
  []
)
const previewRootRef = useRef(null)

const effectiveScheme = forceColorScheme === 'none' ? undefined : forceColorScheme

const form = useMemo(() => ({
  form: {
    key: 'Screen',
    type: 'Screen',
    children: [
      {
        key: 'title',
        type: 'MtTitle',
        props: {
          order: {value: 3},
          children: {value: 'Sign up (' + (effectiveScheme ?? 'default') + '  mode)'}
        }
      },
      {
        key: 'email',
        type: 'MtTextInput',
        props: {
          label: {value: 'Email'},
          placeholder: {value: 'you@example.com'}
        }
      },
      {
        key: 'age',
        type: 'MtSlider',
        props: {
          label: {value: 'Age'},
          min: {value: 13},
          max: {value: 100},
          step: {value: 1}
        }
      },
      {
        key: 'terms',
        type: 'MtCheckbox',
        props: {
          label: {value: 'I agree to terms and privacy policy'}
        }
      }
    ]
  }
}), [effectiveScheme])

const getForm = useCallback(() => JSON.stringify(form), [form])

return (
  <div
    id='mantine-live-root-color'
    ref={previewRootRef}
    style={{
      display: 'grid',
      gap: 12,
      padding: 12,
      borderRadius: 8,
      background: 'var(--mantine-color-body)',
      color: 'var(--mantine-color-text)',
      border: '1px solid var(--mantine-color-default-border)',
      transition: 'background-color 150ms ease, color 150ms ease, border-color 150ms ease'
    }}
  >
    <div style={{display: 'flex', gap: 12, flexWrap: 'wrap'}}>
      <label>
        forceColorScheme:{' '}
        <select
          value={forceColorScheme}
          onChange={(event) => setForceColorScheme(event.target.value)}
        >
          <option value='none'>none</option>
          <option value='light'>light</option>
          <option value='dark'>dark</option>
        </select>
      </label>
    </div>
    <MantineProvider
      colorSchemeManager={colorSchemeManager}
      forceColorScheme={effectiveScheme}
      cssVariablesSelector='#mantine-live-root-color'
      getRootElement={() => previewRootRef.current ?? undefined}
      withGlobalClasses={false}
    >
      <FormViewer view={mantineView} getForm={getForm}/>
    </MantineProvider>
  </div>
)
}

render(<App />)

For color scheme APIs, see:

BiDi support

Mantine supports BiDi setup in several ways:

  1. Wrap the app with DirectionProvider.
  2. Set dir on the root element (html in most apps).
  3. Change direction at runtime with useDirection.
  4. Add RTL-specific CSS overrides with the rtl mixin (when using postcss-preset-mantine).
  5. Configure DirectionProvider behavior with initialDirection and detectDirection.

DirectionProvider

DirectionProvider with MantineProvider
import {DirectionProvider, MantineProvider} from '@mantine/core'
import {view} from '@react-form-builder/components-mantine'
import {FormViewer} from '@react-form-builder/core'

const getForm = () => JSON.stringify({form: {key: 'Screen', type: 'Screen', children: []}})

export const AppWithDirection = () => (
<DirectionProvider initialDirection='ltr'>
<MantineProvider>
<FormViewer view={view} getForm={getForm}/>
</MantineProvider>
</DirectionProvider>
)

Root dir attribute

<!doctype html>
<html dir="rtl">
<head></head>
<body></body>
</html>

Runtime direction switch with useDirection

import {Button, Group, useDirection} from '@mantine/core'

export const DirectionToggle = () => {
const {dir, setDirection, toggleDirection} = useDirection()

return (
<Group>
<Button variant='default' onClick={() => setDirection('ltr')}>LTR</Button>
<Button variant='default' onClick={() => setDirection('rtl')}>RTL</Button>
<Button onClick={toggleDirection}>Toggle ({dir})</Button>
</Group>
)
}

CSS RTL mixin

.demo {
text-align: left;
padding: var(--mantine-spacing-md);

@mixin rtl {
text-align: right;
}
}

For direction support, see RTL direction

Examples

Use these examples to run and inspect viewer and designer integrations:

Viewer example

Result
Loading...
Show code
function App() {
const theme = createTheme({primaryColor: 'cyan'})
const getForm = useCallback(() => JSON.stringify({
  form: {
    key: 'Screen',
    type: 'Screen',
    children: [
      {
        key: 'title',
        type: 'MtTitle',
        props: {
          order: {value: 3},
          children: {value: 'Viewer integration'}
        }
      },
      {
        key: 'name',
        type: 'MtTextInput',
        props: {
          label: {value: 'Name'},
          placeholder: {value: 'John Doe'}
        }
      },
      {
        key: 'submit',
        type: 'MtButton',
        props: {
          children: {value: 'Submit'},
          fullWidth: {value: true}
        }
      }
    ]
  }
}), [])

return (
  <MantineProvider theme={theme}>
    <FormViewer view={mantineView} getForm={getForm}/>
  </MantineProvider>
)
}

render(<App />)

Designer example

For a full designer experience, check the public demo: https://demo.formengine.io/

Designer integration snippet
import {builderView} from '@react-form-builder/components-mantine'
import {FormBuilder} from '@react-form-builder/designer'

import '@mantine/core/styles.css'
import '@mantine/dates/styles.css'
import '@mantine/dropzone/styles.css'
import '@mantine/tiptap/styles.css'

const getForm = () => JSON.stringify({form: {key: 'Screen', type: 'Screen', children: []}})

export const MantineBuilder = () => <FormBuilder view={builderView} getForm={getForm}/>

Component types

Inputs

These components are used for data entry and user input:

ComponentDescriptionMantine Documentation
MtCheckboxCheckbox for binary choicesCheckbox
MtCheckboxGroupGroup of checkboxes for multiple selectionCheckbox
MtChipChip for tags or filtersChip
MtChipCheckboxGroupChip-based checkbox groupChip
MtChipRadioGroupChip-based radio groupChip
MtColorInputColor picker inputColorInput
MtColorPickerColor picker with swatchesColorPicker
MtFileInputFile input with drag-and-dropFileInput
MtDropzoneFile upload dropzoneMantine Dropzone (optional package)
MtJsonInputJSON editor inputJsonInput
MtLabelLabel component for form controlsInput (label)
MtNumberInputNumeric input with optional stepperNumberInput
MtPasswordInputPassword input with visibility togglePasswordInput
MtRadioSingle radio optionRadio
MtRadioGroupRadio button group for single selectionRadio.Group
MtRangeSliderSlider for selecting a range of valuesRangeSlider
MtRatingStar or custom symbol rating inputRating
MtSegmentedControlSegmented control for mutually exclusive optionsSegmentedControl
MtSliderSlider for selecting a value from a rangeSlider
MtSwitchToggle switch for on/off statesSwitch
MtSwitchGroupGroup of switches with a shared labelSwitch.Group
MtTextInputText input field for single-line textTextInput
MtTextareaMulti-line text inputTextarea

Combobox and Select

Dropdown and selection components:

ComponentDescriptionMantine Documentation
MtAutocompleteAutocomplete with suggestionsAutocomplete
MtMultiSelectDropdown for multiple selectionMultiSelect
MtNativeSelectNative HTML select styled with MantineNativeSelect
MtSelectDropdown for single selectionSelect
MtTagsInputInput for multiple tagsTagsInput

Date and Time

Components for date and time selection (require @mantine/dates):

ComponentDescriptionMantine Documentation
MtDateMultiplePickerDate picker for selecting multiple datesMantine Dates
MtDateMultiplePickerInputDate picker input for multiple datesMantine Dates
MtDatePickerDate picker for a single dateMantine Dates
MtDatePickerInputDate picker with input field for a single dateMantine Dates
MtDateRangePickerDate picker for selecting a date rangeMantine Dates
MtDateRangePickerInputDate picker input for a date rangeMantine Dates
MtDateTimePickerDate and time pickerMantine Dates
MtMonthMultiplePickerMonth picker for selecting multiple monthsMantine Dates
MtMonthMultiplePickerInputMonth picker input for multiple monthsMantine Dates
MtMonthPickerMonth picker for a single monthMantine Dates
MtMonthPickerInputMonth picker with input fieldMantine Dates
MtMonthRangePickerMonth picker for selecting a range of monthsMantine Dates
MtMonthRangePickerInputMonth picker input for a range of monthsMantine Dates
MtTimeGridTime slot grid for schedulingMantine Dates
MtTimeInputTime input fieldMantine Dates
MtTimePickerTime pickerMantine Dates
MtYearMultiplePickerYear picker for selecting multiple yearsMantine Dates
MtYearMultiplePickerInputYear picker input for multiple yearsMantine Dates
MtYearPickerYear picker for a single yearMantine Dates
MtYearPickerInputYear picker with input fieldMantine Dates
MtYearRangePickerYear picker for selecting a range of yearsMantine Dates
MtYearRangePickerInputYear picker input for a range of yearsMantine Dates

Layout

ComponentDescriptionMantine Documentation
MtContainerContainer for centering and constraining contentContainer

Typography

ComponentDescriptionMantine Documentation
MtTextText component for body contentText
MtTitleHeading componentTitle
MtTypographyTypography with preset text stylesTypography

Miscellaneous

Miscellaneous utility components:


ComponentDescriptionMantine Documentation
MtDividerVisual dividerDivider
MtErrorWrapperError display wrapperCustom component for error handling
MtViewerWrapperWrapper component for viewersCustom component for viewer integration

Other extensions

Additional Mantine-based extensions:

ComponentDescriptionMantine Documentation
MtTiptapRich text editorMantine Tiptap (optional package)
MtDropzoneFile upload dropzoneMantine Dropzone (optional package)

Overlays

ComponentDescriptionMantine Documentation
MtTooltipTooltip for additional infoTooltip
ComponentDescriptionMantine Documentation
MtDialogModal dialog containerModal

Buttons

ComponentDescriptionMantine Documentation
MtButtonButton for user actionsButton

Additional Resources

Support

For issues with Mantine components in FormEngine:

Mantine components provide a modern, accessible, and themable way to build forms and interfaces in FormEngine applications, with strong TypeScript support and responsive design out of the box.