Tina's "click to edit" feature allows editors to select the HTML element they want to click on the page in order to see the corresponding field in the sidebar.
We can implement this with the data-tina-field
API.
[data-tina-field]
cannot be applied directly to React components, such as TinaMarkdown.
The object which holds the field you're accessing.
The property from the object which you're accessing, omitting this will return the object field's metadata.
All properties marked as REQUIRED must be specified for the field to work properly.
Note: Theobject
property only needs to contain the nearest ancestor of the field you're trying to access.
// components/blocks/heroimport { tinaField } from 'tinacms/dist/react';export const HeroComponent = (props) => {return (<div><h4 data-tina-field={tinaField(props, 'heading')}>{props.heading}</h4><p data-tina-field={tinaField(props, 'message')}>{props.message}</p><ul data-tina-field={tinaField(props, 'links')}>{props.links.map((link) => (<li><a data-tina-field={tinaField(link)} href={link.url}>{link.label}</a></li>))}</ul></div>);};
Notice that the <a>
tag's data attribute only needs access to the link
data object.
When Tina finds an element with the [data-tina-field]
attribute, it will attach some CSS to it when in edit mode, clicking on the element triggers
the Tina form to open and focus the matching field.
Since Tina uses CSS to achieve the interface, it's possible for styles to collide. Overriding and customizing Tina's styles are encouraged. Here's an example of overriding the outline color to red:
.__tina-quick-editing-enabled [data-tina-field] {outline: 2px dashed rgba(254, 34, 56, 0.5);}.__tina-quick-editing-enabled [data-tina-field]:hover {outline: 2px dashed rgba(254, 34, 56, 1);}
tinaField
helper work?In order for this to work, Tina needs to know what document and field the
element is associated with. Tina makes this easy with the tinaField
helper
function. Using this function, developers can add the appropriate metadata
to the [data-tina-field]
attribute.
import { useTina, tinaField } from 'tinacms/dist/react';const Page = (props) => {const { data } = useTina(props);return (<div><h1 data-tina-field={tinaField(data, 'title')}>{data.title}</h1></div>);};
Now, when you open the Tina sidebar you'll see editing overlays on any element that's been configured.
"Click to edit" will work for any field in your query, this means you can also click on fields from references as well.
The tinaField
function used above is a type-safe helper designed to pluck the metadata out of the data object for the given
property to be used on the [data-tina-field]
attribute:
// Get metadata for the 'object' fieldtinaField(data);// Get metadata for the `data.title` fieldtinaField(data, 'title');
When not in edit-mode, the data
returned by the useTina
hook might look like this:
{page: {title: 'Hello, world',blocks: [{__typename: 'PageBlocksHero',heading: 'Hi, again!',description: 'Some description'links: [{label: "About Us",url: '/about=us'}]}]}}
Once edit-mode is enabled, Tina will update each nested object with _tina_metadata
:
{page: {title: 'Hello, world',blocks: [{__typename: 'PageBlocksHero',heading: 'Hi, again!',description: 'Some description'links: [{label: "About Us",url: '/about=us',_tina_metadata: {formId: "content/pages/hello-world.md",fields: {// tinaField(link, 'label') -> `023nsk-page.blocks.0.links.0.label`label: "page.blocks.0.links.0.label",url: "page.blocks.0.links.0.link",}}}],_tina_metadata: {...}}],_tina_metadata: {...}}}
The tinaField
helper simply plucks out the appropriate information from the _tina_metadata
object.
tinaField
with custom React componentsThe [data-tina-field]
attribute can only be applied directly to HTML elements. This makes it tricky to use with React components because attribute names need to have kebab case. Instead we can define a prop on our React component allowing us to pass tinaField
in.
import { useTina, tinaField } from 'tinacms/dist/react';import { TinaMarkdown } from 'tinacms/dist/rich-text';const Page = (props) => {const { data } = useTina(props);return (<Section tinaField={tinaField(data, 'body')}><TinaMarkdown content={data.body} /></Section>);};type SectionProps = {children?: React.ReactNode,tinaField?: string,};// defining a tinaField property (the name is arbitrary)const Section = ({ children, tinaField }: SectionProps) => {//passing the tina field information to our html elementreturn <section data-tina-field={tinaField}>{children}</section>;};
© TinaCMS 2019–2025