There are two ways to create custom fields with Tina:
component
propertyA field Component
is React component that accepts three props:
field
: The field definition for the current field.input
: The data and callbacks necessary to make an input.meta
: Metadata about the field in the form. (e.g. dirty
, valid
)Checkout the react-final-form docs for a more detailed description of the input
and meta
props.
Checkout this blog for a step-by-step guide on creating a custom field component.
A field plugin is a JavaScript object with three properties:
name
: A string used to identify the component. This is the name that is set in a field definition. This name must be unique; if multiple plugins are registered with the same name, only the last will be used.Component
: The component that will used in the form. The exact nature of this component depends on which form builder is being used.validate
: An optional function that will be used to validate the field's data.Interface
interface FieldPlugin {
__type: 'field'
name: string
Component: React.FC<any>
type?: string
validate?(
value: any,
allValues: any,
meta: any,
field: Field
): string | object | undefined
parse?: (value: any, name: string, field: Field) => any
format?: (value: any, name: string, field: Field) => any
defaultValue?: any
}
Checkout this blog for a more in-depth look at creating custom field plugins.
The optional validate
function can be utilized to configure field validation.
Arguments
value
: The field's current valueallValues
: The current state of the entire formmeta
: The form metadata for this fieldfield
: The field's configurationimport { MapPicker, validateMap } from 'cms-field-my-map-picker'
let cms = new CMS()
cms.fields.add({
name: 'map',
Component: MapPicker,
validate: validateMap,
})
Here is an example of a simple text field plugin. The Component
renders the label, the input, and the errors for the field.
import { CMS } from '@tinacms/core'
let cms = new CMS()
cms.fields.add({
name: 'text',
Component({ input, meta, field }) {
return (
<div>
<label htmlFor={input.name}>{field.label || field.name}</label>
<div>{field.description}</div>
<input type="email" {...input} />
<div className="field-error">{meta.error}</div>
</div>
)
},
validate(email, allValues, meta, field) {
let isValidEmail = /.*@.*\..*/.test(email)
if (!isValidEmail) return 'Invalid email address'
},
})
If you want to style the custom field to fit in with the rest of the Tina sidebar, you'll need to use the CSS custom properties defined in @tinacms/styles
.
Example
import styled from 'styled-components'
// Use the Tina CSS variables in your styled component
const Label = styled.h3`
color: var(--tina-color-primary);
font-size: var(--tina-font-size-3);
font-weight: var(--tina-font-weight-bold);
border-radius: var(--tina-radius-big);
border: 1px solid var(--tina-color-primary-light);
transition: color linear ease var(--tina-timing-medium);
padding: var(--tina-padding-small);
`