Skip to main content
Version: Next

Array inputs

Formulaik can render an array of inputs that have the same component. This is useful when you want the user to add new inputs with a fixed type (component).

There are some differences with a regular input:

  • The input is an abstraction of an array of inputs. Thus it does not declare a component.
  • It declares the components needed for the container. The container component is declared the same way a regular input component is
  • It declares the abstract compponents in params. This is where you declare the input template.
  • The special placeholder field in params will provide the default value needed to instantiate a new element in the array
  • Add isList: true to declare this input as an array input
  • Use canRemove, showRemove, canAddItems, canMove, showControls, maxItems and isHorizontal to configure the input

Example​

This code will create a form for the user to add questions at will:

const inputs = [
{
id: 'choices',
label: 'Choices',
isList: true,
canRemove: true,
showRemove: false,
canAddItems: true,
canMove: true,
showControls: true,
maxItems: 4,
isHorizontal: true,
className: 'py-2',
label: 'Questions',
add: {
type: '_buttonAdd',
title: MPI18nT("Add a choice")
},
container: {
type: '_containerHorizontal',
title: ({ value, index }) => null,
className: ''
},
params: {
component: 'questionchoicetext',
id: 'choice',
label: 'Choice',
params: {
placeholder: async () => {
return {
content: '',
}
},
}
}
},
{
component: 'submit',
id: 'submit',
params: {
text: 'Continue'
}
},
]
  • It uses the _containerHorizontal component
import React from 'react'
import IconButton from '@mui/material/IconButton'

import { Trash, ChevronLeft, ChevronRight } from 'react-feather'

export default (props) => {
const {
summary,
title,
children,
onMoveDownRequired,
onRemoveRequired,
onMoveUpRequired,
canRemove,
canMoveUp,
canMoveDown,
showControls,
disabled = false,
readOnly = false,
value,
index,
className,
error
} = props

return <div className={`
border-warmGray-200
hover:border-warmGray-300
transition-all
ease-in-out
duration-300
border-2
py-1
rounded-xl ${className}`}>
<div className='
border-b
border-warmGray-100
px-2
py-1
flex justify-end mr-4'>
{summary && summary({ value, index })}
{showControls && <div className='flex gap-3'>
<IconButton aria-label="Move up" disabled={disabled || !canMoveUp} component="span"
onClick={(e) => {
e.preventDefault()
e.stopPropagation()
onMoveUpRequired && onMoveUpRequired()
}} >
<ChevronLeft
size={20}
/>
</IconButton>
<IconButton aria-label="Move down" disabled={disabled || !canMoveDown} component="span"
onClick={(e) => {
e.preventDefault()
e.stopPropagation()
onMoveDownRequired && onMoveDownRequired()
}}>
<ChevronRight
size={20}
/>
</IconButton>
<IconButton aria-label="Delete" disabled={disabled} component="span"
onClick={(e) => {
e.preventDefault()
e.stopPropagation()
onRemoveRequired && onRemoveRequired()
}} >
{canRemove &&
<Trash
size={20}
/>}
</IconButton>
</div>
}
</div>
<div className='px-1'>
{children}
</div>
</div>
}
`