{"pageProps":{"error":null,"preview":false,"file":{"fileRelativePath":"content/docs/ui/inline-editing/inline-blocks.md","data":{"frontmatter":{"title":"Inline Blocks","prev":"/docs/ui/inline-editing/inline-group","next":null,"consumes":[{"file":"/packages/react-tinacms-inline/src/inline-form.tsx","description":"InlineForm"},{"file":"/packages/react-tinacms-inline/src/blocks/block.ts","description":"Shows Block interface"},{"file":"/packages/@tinacms/fields/src/plugins/BlocksFieldPlugin.tsx","description":"Shows Block Template interface"},{"file":"/packages/react-tinacms-inline/src/blocks/inline-field-blocks.tsx","description":"Shows Inline Blocks interface and gives example"},{"file":"/packages/react-modals/src/ModalProvider.tsx","description":"Uses ModalProvider for Block Settings"}]},"excerpt":" Inline Blocks combine the content modelling flexibility of regular Blocks with the improved editing experience of Inline Editing. Learn about Inline Blocks in a step-by-step guide! Creating a Block A…","markdownBody":"\nInline Blocks combine the content modelling flexibility of regular [Blocks](/blog/what-are-blocks) with the improved editing experience of [Inline Editing](/docs/ui/inline-editing).\n\n> Learn about Inline Blocks in a [step-by-step guide](/guides/general/inline-blocks/overview)!\n\n## Creating a Block\n\nA _block_ is **made of two parts**: _a component_ that renders in edit mode, and _a template_ to configure fields, defaults and other required data.\n\n```ts\ninterface Block {\n Component: React.FC\n template: BlockTemplate\n}\n```\n\n### Part 1: Block Component\n\n```jsx\nimport { BlocksControls, InlineTextarea } from 'react-tinacms-inline'\n\n// Example 'Heading' Block\nexport function Heading(props) {\n return (\n \n \n \n )\n}\n```\n\nThe _Block Component_ is passed `index`, its position in the block order, and `data`, the source data.\n\n```ts\ninterface BlockComponentProps {\n index: number\n data: any\n}\n```\n\nSince it **renders in 'edit mode,'** this component should display `BlocksControls` and at least one _Inline Field_. `BlocksControls` is the UI for editing, deleting, or moving blocks. An _Inline Field_ is, at its most basic, an input field stripped of styling to blend in with the site.\n\n#### Blocks Controls Options\n\n| Key | Description |\n| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `index` | The index of the block associated with these controls. |\n| `insetControls` | A boolean to denote whether the group controls display within or outside the group. |\n| `focusRing` | Either an object to style the focus ring or `false`, which hides the focus ring entirely. For styles, `offset` (in pixels) controls the distance from the ring to the edge of the group; `borderRadius`(in pixels) controls the [rounding](https://developer.mozilla.org/en-US/docs/Web/CSS/border-radius) edge of the focus ring. |\n| `children` | Any child components, typically inline field(s). |\n\n```ts\ninterface BlocksControlsProps {\n index: number\n insetControls?: boolean\n focusRing?: false | FocusRingProps\n children: any\n}\n\ninterface FocusRingProps {\n offset?: number | { x: number; y: number }\n borderRadius?: number\n}\n```\n\n\n\n![TinaCMS: Inline Block Controls](/img/inline-blocks/blocks-controls-redo.png)\n\nThe image above shows the _InlineTextarea_ field in use with Blocks Controls.\n\n**Additional Available Inline Fields**:\n\n- [Text](/docs/ui/inline-editing/inline-text)\n- [Textarea](/docs/ui/inline-editing/inline-textarea)\n- [Image](/docs/ui/inline-editing/inline-image)\n- [Group](/docs/ui/inline-editing/inline-group)\n\n### Part 2: Block Template\n\n```jsx\nexport const heading_template = {\n type: 'heading',\n label: 'Heading',\n defaultItem: {\n text: 'At vero eos et accusamus',\n },\n key: 'heading-block',\n fields: [],\n}\n```\n\nThe _Inline Block Template_ **configures the block** with the CMS. It has a similar shape to a Regular [Block Template](/docs/plugins/fields/blocks#block-template-options) definition.\n\n| Key | Type | Purpose |\n| -------------- | :--------------------------: | ---------------------------------------------------------------------------------------------------: |\n| `type` | `string` | This value connects source block data with the template. |\n| `label` | `string` | A human readable label. |\n| `defaultItem?` | `object \\\\\\| (() => object)` | Populates new blocks with default data. |\n| `key` | `string` | A unique value to optimize the [rendering of the list](https://reactjs.org/docs/lists-and-keys.html) |\n| `fields` | `Array` | Populates fields in the [Settings Modal](link to settings modal). |\n\n## Configuring Inline Blocks with Inline Form\n\nThe initial steps to configuring _Inline Blocks_ involve setting up an _[Inline Form](/docs/ui/inline-editing#inlineform-and-inlinefield)_ on the page or component where the blocks should render. Then, you should [add controls](/docs/ui/inline-editing#inline-form-controls) to handle editing state. Finally, you can use a component called `InlineBlocks` that **renders blocks in order** based on the source data.\n\n### The Steps:\n\n1. Wrap your component with `InlineForm`, pass the `form` object.\n2. Set up [Inline Controls](/docs/ui/inline-editing#inline-form-controls).\n3. Configure `InlineBlocks`, pass the `name` and `blocks` values.\n\n```jsx\nimport { useJsonForm } from 'next-tinacms-json'\nimport { InlineForm, InlineBlocks } from 'react-tinacms-inline'\nimport {\n BodyCopy,\n body_copy_template,\n Heading,\n heading_template,\n Image,\n image_template,\n} from './blocks'\nimport { EditToggle, DiscardButton, SaveButton } from './inline-ui'\n\n/*\n ** Example 'PageBlocks' Component\n */\n\nexport default function PageBlocks({ jsonFile }) {\n // Creates the form\n const [, form] = useJsonForm(jsonFile)\n\n return (\n \n \n \n \n \n \n )\n}\n\n/*\n ** Multiple blocks are grouped into a single object,\n ** with their associated Component and template values.\n ** This object is passed to InlineBlocks\n */\n\nconst PAGE_BLOCKS = {\n heading: {\n Component: Heading,\n template: heading_template,\n },\n body_copy: {\n Component: BodyCopy,\n template: body_copy_template,\n },\n image: {\n Component: Image,\n template: image_template,\n },\n}\n```\n\n### _InlineBlocks_ Interface\n\nTo be configured properly, `InlineBlocks` requires `name` and `blocks`.\n\n```ts\ninterface InlineBlocksProps {\n name: string\n blocks: {\n [key: string]: Block\n }\n className?: string\n direction?: 'vertical' | 'horizontal'\n itemProps?: {\n [key: string]: any\n }\n min?: number\n max?: number\n}\n```\n\n| Key | Purpose |\n| ----------- | ----------------------------------------------------------------------------------------------------------------------------: |\n| `name` | The path to the **source data** for the blocks. |\n| `blocks` | An object composed of individual [Blocks](/docs/ui/inline-editing/inline-blocks#creating-a-block). |\n| `className` | To set styles directly on the input or extend via [styled components](/docs/ui/inline-editing#extending-inline-field-styles). |\n| `direction` | Sets the orientation of the drag direction and `AddBlock` button position. |\n| `itemProps` | An object that passes additional props to every block child element. |\n| `min` | Controls the minimum number of blocks. Once reached, blocks won't be able to be removed. _(Optional)_ |\n| `max` | Controls the maximum number of blocks allowed. Once reached, blocks won't be able to be added. _(Optional)_ |\n\n### Blocks Source Data\n\nThe source data for the blocks in the example above could look something like this:\n\n```json\n// Example blocks JSON source file\n{\n \"blocks\": [\n {\n \"_template\": \"image\",\n \"src\": \"/img/bali-1.jpg\",\n \"alt\": \"bali-viaje\"\n },\n {\n \"_template\": \"heading\",\n \"text\": \"Ne quaesiveris extra.\"\n },\n {\n \"_template\": \"body_copy\",\n \"text\": \"Sed ut perspiciatis unde omnis iste natus error.\"\n }\n ]\n}\n```\n\nThe key (\"blocks\" in this example) for the array of individual blocks must match the `name` value passed to `InlineBlocks`.\n\nEach individual _block_ object must have a `_template` value to connect its data with a block template. This value should match the `type` value defined in the associated block template.\n\n## Using the Settings Modal\n\nThere may be times when a _Block_ **needs more field inputs** than a single inline field. For example, an image may need a field for the ‘alt’ tag. For this metadata, you can use `ModalProvider` and add additional fields to the _Block Template_.\n\n![TinaCMS: Inline Blocks Settings Modal](/img/inline-blocks/settings-modal.png)\n\n### 1. Define Fields in the Block Template\n\nField definitions added to the `fields` property will render in the _Settings Modal_. These fields are defined exactly the same as regular [sidebar fields](/docs/plugins/fields).\n\n```js\nconst image_template = {\n type: 'image',\n label: 'Image',\n defaultItem: {\n src: '/img/bali-1.jpg',\n alt: '',\n },\n key: 'image-block',\n /*\n ** Define fields to render\n ** in a Settings Modal form\n */\n fields: [\n {\n name: 'alt',\n label: 'Alt Text',\n component: 'text',\n },\n ],\n}\n```\n\n### 2. Use the field data in your Block Component\n\nYou can then use that field data in the Block Component. In this example, the data will populate the `alt` attribute for the image.\n\n```jsx\nexport function Image({ data, index }) {\n return (\n <>\n
\n \n formValues.blocks[index].src}\n parse={filename => `/img/${filename}`}\n uploadDir={() => '/public/img/'}\n >\n {/*\n ** The 'alt' data from the\n ** 'settings' is consumed\n */}\n {data.alt}\n \n \n
\n \n )\n}\n```\n\n### 3. Add the `ModalProvider`\n\nTo use the `ModalProvider`, wrap it around the `InlineForm` that renders `InlineBlocks`. This will provide the _Settings Modal_ view. The fields defined in the block template will **populate the form** in that modal.\n\n```jsx\nimport { useJsonForm } from 'next-tinacms-json'\nimport { ModalProvider } from 'tinacms'\nimport { InlineForm, InlineBlocks } from 'react-tinacms-inline'\n\nexport default function IndexBlocks({ jsonFile }) {\n const [, form] = useJsonForm(jsonFile)\n\n // Wrap InlineForm with the ModalProvider\n return (\n \n \n {/*\n ** //...\n */}\n \n \n )\n}\n```\n\n\n"}},"tocItems":"- [Creating a Block](#creating-a-block)\n * [Part 1: Block Component](#part-1-block-component)\n + [Blocks Controls Options](#blocks-controls-options)\n * [Part 2: Block Template](#part-2-block-template)\n- [Configuring Inline Blocks with Inline Form](#configuring-inline-blocks-with-inline-form)\n * [The Steps:](#the-steps)\n * [_InlineBlocks_ Interface](#inlineblocks-interface)\n * [Blocks Source Data](#blocks-source-data)\n- [Using the Settings Modal](#using-the-settings-modal)\n * [1. Define Fields in the Block Template](#1-define-fields-in-the-block-template)\n * [2. Use the field data in your Block Component](#2-use-the-field-data-in-your-block-component)\n * [3. Add the `ModalProvider`](#3-add-the-modalprovider)","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":null,"title":null},"prevPage":{"slug":"/docs/ui/inline-editing/inline-group","title":"Inline Group"}},"__N_SSG":true}