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);
`