{"pageProps":{"error":null,"preview":false,"file":{"fileRelativePath":"content/docs/ui/inline-editing/inline-image.md","data":{"frontmatter":{"title":"Inline Image","prev":"/docs/ui/inline-editing/inline-wysiwyg","next":"/docs/ui/inline-editing/inline-group","consumes":[{"file":"/packages/react-tinacms-inline/src/inline-field-image.tsx","description":"Shows InlineImage"},{"file":"/packages/react-tinacms-inline/src/inline-field.tsx","description":"Depends on InlineField"}]},"excerpt":" The InlineImage field represents an image input. This field supports drag and drop upload, or via clicking on the image to select media from the local filesystem. Definition Below is a simple example…","markdownBody":"\nThe `InlineImage` field represents an image input. This field supports drag and drop upload, or via clicking on the image to select media from the local filesystem.\n\n## Definition\n\nBelow is a simple example of how `InlineImage` could be implemented in in an [Inline Form](/docs/ui/inline-editing).\n\n```jsx\nimport ReactMarkdown from 'react-markdown'\nimport { useLocalForm } from 'tinacms'\nimport { InlineForm, InlineImage } from 'react-tinacms-inline'\n\n// Example 'Page' Component\nexport function Page(props) {\n const [data, form] = useLocalForm(props.data)\n return (\n \n `/images/${filename}`}\n uploadDir={() => '/public/images/'}\n previewSrc={formValues => {}}\n />\n \n )\n}\n```\n\nThere are two ways to use `InlineImage`, with and without children. If no children are passed, `InlineImage` will render a default `img` element. However, you may want more control over the image behavior, in which case you can [**pass children**](/docs/ui/inline-editing/inline-image#example) to `InlineImage`.\n\n## Options\n\n| Key | Description |\n| ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `name` | The path to some value in the data being edited. |\n| `parse` | Defines how the actual front matter or data value gets populated. The name of the file gets passed as an argument, and one can set the path this image as defined by the uploadDir property. |\n| `uploadDir` | Defines the upload directory for the image. All of the post data is passed in, `fileRelativePath` is most useful in defining the upload directory, but you can also statically define the upload directory. |\n| `previewSrc` | Defines the path for the src attribute on the image preview. If using gatsby-image, the path to the `childImageSharp.fluid.src` needs to be provided. |\n| `focusRing` | Controls whether to display a focus outline. |\n| `children` | Children need to be passed through the [Render Props](https://reactjs.org/docs/render-props.html) pattern to access `previewSrc`. |\n\n---\n\n## Interface\n\n```typescript\ninterface InlineImageProps {\n name: string\n parse(filename: string): string\n uploadDir(form: Form): string\n previewSrc(formValues: any): string\n focusRing?: boolean\n children?: any\n}\n```\n\nThe `parse` function handles how the path gets written in the source data when a _new image_ is uploaded. `parse` is passed the filename of the newly uploaded image — `image.jpg`. A simple return value could look something like this:\n\n```js\nparse: filename => `/example-dir/${filename}`\n```\n\nThe path **depends on where images live** in your project structure. `uploadDir` sets where those new images should live:\n\n```js\nuploadDir: () => `/example-dir`\n```\n\nThe `previewSrc` provides a path for the image **when inline editing is active** (a.k.a when the [CMS is enabled](https://tinacms.org/docs/cms#disabling--enabling-the-cms)). When inline editing is not active (`cms.enabled === false`), the image will reference the path in the source data. `previewSrc` is passed **current form values** as its first argument.\n\n## Examples\n\n### _previewSrc_ with blocks\n\nIf using `InlineImage` as a block, use these values, along with the block `index` to target the proper image source from the data.\n\n```js\n/**\n * `index` is passed as props to the block component\n * that renders the inline image\n */\nfunction ImageBlock({ index }) {\n return (\n \n
\n `/assets/${filename}`}\n uploadDir={() => '/public/assets'}\n previewSrc={formValues => `${formValues.blocks[index].left.src}`}\n focusRing={false}\n />\n
\n
\n )\n}\n```\n\nThe return value should be the entire path to the image from the source data — e.g. `/example-dir/image.jpg`.\n\n### Accessing block index in the template fields\n\nUsing the `index` in the `previewSrc` to target the correct block is very helpful. While `index` is passed to the _Block Component_, it is not directly available in the _Block Template_.\n\nOne way to work around this is to access the second argument, `input`. Manipulate the form input data to get the index of the current field.\n\nSee the example below for a variation on getting the block index:\n\n**components/Images.js**\n\n```jsx\nexport const imagesBlock = {\n Component: Images,\n template: {\n //... Other block template config\n fields: [\n {\n name: 'left.src',\n label: 'Left-Hand Image',\n component: 'image',\n parse: filename => `/${filename}`,\n uploadDir: () => '/',\n previewSrc: (formValues, input) => {\n /**\n * Get index from field input. Assumes the block\n * is only one level deep\n */\n const index = input.field.name.split('.')[1]\n /**\n * Use that index to target the correct\n * block in `formValues`\n */\n const currentBlockImage = formValues.blocks[index].left.src\n return currentBlockImage\n },\n focusRing: false,\n },\n {\n name: 'left.alt',\n label: 'Left-Hand Image Alt Text',\n component: 'text',\n },\n {\n name: 'right.src',\n label: 'Right-Hand Image',\n component: 'image',\n parse: filename => `/${filename}`,\n uploadDir: () => '/',\n previewSrc: (formValues, input) => {\n const index = input.field.name.split('.')[1]\n const currentBlockImage = formValues.blocks[index].right.src\n return currentBlockImage\n },\n focusRing: false,\n },\n {\n name: 'right.alt',\n label: 'Right-Hand Image Alt Text',\n component: 'text',\n },\n ],\n },\n}\n```\n\n### Passing children with Gatsby Image\n\nBelow is an example of how you could **pass children** as a to `InlineImage` to work with _Gatsby Image_. Notice how _children_ **need to be passed via** [**render props**](https://reactjs.org/docs/render-props.html).\n\nThe return value from the `previewSrc` function is passed as a prop. You can use this as the Img src when the CMS is enabled. This allows it so when new images are uploaded, the correct `previewSrc` should render. A fallback `src` should be provided based on the form data — this will be the `src` when the CMS is disabled.\n\nRead more on [proper image paths](/docs/plugins/fields/image#proper-image-paths-in-gatsby) in Gatsby to get context on the `parse` & `uploadDir` configuration.\n\n```jsx\nimport {\n Inlineform,\n InlineImage,\n InlineTextareaField,\n} from 'react-tinacms-inline'\nimport { useRemarkForm } from 'gatsby-tinacms-remark'\nimport { usePlugin } from 'tinacms'\nimport Img from 'gatsby-image'\n\n// Using InlineImage with Gatsby Image\nexport function Hero({ data }) {\n const [post, form] = useRemarkForm(data.markdownRemark)\n\n usePlugin(form)\n\n return (\n \n (filename ? `./${filename}` : null)}\n uploadDir={blogPost => {\n const postPathParts = blogPost.initialValues.fileRelativePath.split(\n '/'\n )\n\n const postDirectory = postPathParts\n .splice(0, postPathParts.length - 1)\n .join('/')\n\n return postDirectory\n }}\n previewSrc={formValues => {\n const preview =\n formValues.frontmatter.thumbnail.childImageSharp.fluid.src\n return preview\n }}\n >\n {props => (\n \n )}\n \n

\n \n

\n
\n )\n}\n```\n\n\n"}},"tocItems":"- [Definition](#definition)\n- [Options](#options)\n- [Interface](#interface)\n- [Examples](#examples)\n * [_previewSrc_ with blocks](#previewsrc-with-blocks)\n * [Accessing block index in the template fields](#accessing-block-index-in-the-template-fields)\n * [Passing children with Gatsby Image](#passing-children-with-gatsby-image)","docsNav":[{"title":"Getting Started","id":"getting-started","items":[{"id":"/docs/getting-started/introduction","slug":"/docs/getting-started/introduction","title":"Introduction"}]},{"title":"CMS","id":"the-cms","items":[{"id":"/docs/cms","slug":"/docs/cms","title":"Overview"}]},{"title":"User Interface","id":"user-interface","items":[{"id":"/docs/ui","title":"Sidebar & Toolbar","slug":"/docs/ui"},{"title":"Inline Editing","id":"inline-editing","slug":"/docs/ui/inline-editing","items":[{"id":"/docs/ui/inline-editing/inline-text","title":"Inline Text","slug":"/docs/ui/inline-editing/inline-text"},{"id":"/docs/ui/inline-editing/inline-textarea","title":"Inline Textarea","slug":"/docs/ui/inline-editing/inline-textarea"},{"id":"/docs/ui/inline-editing/inline-wysiwyg","title":"Inline Wysiwyg","slug":"/docs/ui/inline-editing/inline-wysiwyg"},{"id":"/docs/ui/inline-editing/inline-image","title":"Inline Image","slug":"/docs/ui/inline-editing/inline-image"},{"id":"/docs/ui/inline-editing/inline-group","title":"Inline Group","slug":"/docs/ui/inline-editing/inline-group"},{"id":"/docs/ui/inline-editing/inline-blocks","title":"Inline Blocks","slug":"/docs/ui/inline-editing/inline-blocks"}]},{"id":"/docs/ui/alerts","title":"Alerts","slug":"/docs/ui/alerts"},{"id":"/docs/ui/styles","title":"Custom Styles","slug":"/docs/ui/styles"}]},{"id":"plugins","title":"Plugins","items":[{"title":"About Plugins","id":"forms","slug":"/docs/plugins"},{"title":"Forms","id":"forms","slug":"/docs/plugins/forms"},{"title":"Fields","id":"fields","slug":"/docs/plugins/fields","items":[{"id":"/docs/plugins/fields/text","slug":"/docs/plugins/fields/text","title":"Text"},{"id":"/docs/plugins/fields/textarea","slug":"/docs/plugins/fields/textarea","title":"Text Area"},{"id":"/docs/plugins/fields/number","slug":"/docs/plugins/fields/number","title":"Number"},{"id":"/docs/plugins/fields/image","slug":"/docs/plugins/fields/image","title":"Image"},{"id":"/docs/plugins/fields/color","slug":"/docs/plugins/fields/color","title":"Color"},{"id":"/docs/plugins/fields/toggle","slug":"/docs/plugins/fields/toggle","title":"Toggle"},{"id":"/docs/plugins/fields/select","slug":"/docs/plugins/fields/select","title":"Select"},{"id":"/docs/plugins/fields/tags","slug":"/docs/plugins/fields/tags","title":"Tags"},{"id":"/docs/plugins/fields/list","slug":"/docs/plugins/fields/list","title":"List"},{"id":"/docs/plugins/fields/group","slug":"/docs/plugins/fields/group","title":"Group"},{"id":"/docs/plugins/fields/group-list","slug":"/docs/plugins/fields/group-list","title":"Group List"},{"id":"/docs/plugins/fields/blocks","slug":"/docs/plugins/fields/blocks","title":"Blocks"},{"id":"/docs/plugins/fields/date","slug":"/docs/plugins/fields/date","title":"Date & Time"},{"id":"/docs/plugins/fields/markdown","slug":"/docs/plugins/fields/markdown","title":"Markdown"},{"id":"/docs/plugins/fields/html","slug":"/docs/plugins/fields/html","title":"HTML"},{"id":"/docs/plugins/fields/custom-fields","slug":"/docs/plugins/fields/custom-fields","title":"Custom Fields"}]},{"title":"Content Creators","id":"content-creator","slug":"/docs/plugins/content-creators"},{"title":"Screens","id":"screens","slug":"/docs/plugins/screens"},{"title":"Toolbar Widgets","id":"toolbar:widget","slug":"/docs/plugins/toolbar-widgets"}]},{"id":"events","title":"Events","items":[{"id":"/docs/events","slug":"/docs/events","title":"About Events"}]},{"title":"Media","id":"media","items":[{"id":"/docs/media","slug":"/docs/media","title":"About Media"}]},{"id":"apis","title":"External APIs","items":[{"id":"/docs/api","slug":"/docs/apis","title":"About APIs"}]},{"title":"Integrations","id":"nextjs","items":[{"id":"/docs/integrations/nextjs","slug":"/docs/integrations/nextjs","title":"Next.js"},{"id":"/docs/integrations/gatsby","slug":"/docs/integrations/gatsby","title":"Gatsby"}]},{"title":"Release Notes","id":"releases","items":[{"id":"/docs/releases","href":"/docs/releases","title":"All Releases"}]},{"title":"Packages","id":"packages","items":[{"id":"/packages/react-tinacms-date","slug":"/packages/react-tinacms-date","title":"react-tinacms-date"},{"id":"/packages/react-tinacms-editor","slug":"/packages/react-tinacms-editor","title":"react-tinacms-editor"},{"id":"/packages/react-tinacms-github","slug":"/packages/react-tinacms-github","title":"react-tinacms-github"},{"id":"/packages/react-tinacms-inline","slug":"/packages/react-tinacms-inline","title":"react-tinacms-inline"},{"id":"/packages/react-tinacms-strapi","slug":"/packages/react-tinacms-strapi","title":"react-tinacms-strapi"},{"id":"/packages/next-tinacms-github","slug":"/packages/next-tinacms-github","title":"next-tinacms-github"},{"id":"/packages/next-tinacms-json","slug":"/packages/next-tinacms-json","title":"next-tinacms-json"},{"id":"/packages/next-tinacms-markdown","slug":"/packages/next-tinacms-markdown","title":"next-tinacms-markdown"},{"id":"/packages/gatsby-plugin-tinacms","slug":"/packages/gatsby-plugin-tinacms","title":"gatsby-plugin-tinacms"},{"id":"/packages/gatsby-tinacms-git","slug":"/packages/gatsby-tinacms-git","title":"gatsby-tinacms-git"},{"id":"/packages/gatsby-tinacms-json","slug":"/packages/gatsby-tinacms-json","title":"gatsby-tinacms-json"},{"id":"/packages/gatsby-tinacms-remark","slug":"/packages/gatsby-tinacms-remark","title":"gatsby-tinacms-remark"}]}],"nextPage":{"slug":"/docs/ui/inline-editing/inline-group","title":"Inline Group"},"prevPage":{"slug":"/docs/ui/inline-editing/inline-wysiwyg","title":"Inline Wysiwyg"}},"__N_SSG":true}