---
title: Improve publishing with inline edit blocks
slug: cms-12/docs/inline-edit-settings
docTags: 
createdAt: 2026-08-10T15:56:04.000Z
---

## CMS UI 12.22.3 and newer

Inline blocks are turned off by default, but from version 12.22.3, you can opt-in so that whenever you create a new block from a `ContentArea` property, you create an inline block stored inside the parent content item.

Inline blocks are no longer `IContent` instances. Instead, they are just property bags stored inside `ContentAreaItem`.

Inline blocks do not have a `Name` or `ContentLink` or other base properties.

For example, if there is a block type defined in the following way:

```csharp
[ContentType(Guid = "67F617A4-2175-4360-975E-75EDF2B924A7")]
public class TeaserBlock: BlockData {
  public virtual string Foo {
    get;
    set;
  }
}
```

If you add an instance of `TeaserBlock` to the **Assets** panel as a shared block then it has the properties implemented from `IContent` such as `Name`, `ID`, and so on.

However, if you decide to add `TeaserBlock` through `Create a new block` link in Content Area, then it prompts the editor to enter the value for the `Foo` string property and serializes that object and stores it inside the `ContentAreaItem.InlineBlock` property.

It does not have `ContentLink` of its own. It does not have a publishing or approval lifecycle of its own but will be managed only through its parent content.

You cannot differentiate inline blocks; they are just shown as block types.

:::hint{type="warning"}
**Caution**
\`\`InlineBlockEditSettings\` is being obsoleted and will be removed in CMS 13.
:::

`ILocalAssetNameGenerator`does not influence Inline Blocks because, as stated above, inline blocks do not have `Name` property on their own.

Inline blocks are convenient in on-page editing. However, it can be difficult to distinguish them in **All Properties** view because those blocks are no longer `IContent` and thus have no `Name` property on their own.

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/hNO_3gVJrt2YJHuQ_8ABC-20260722-184800.png)Inline block labels are their type names, which is fine if there are just a few, but if the list of blocks is long, it may become problematic to find the block you want to edit (because, in contrast to the on-page editing, you do not see the view of the block). You can instruct `ContentArea` to use a specific property from block type as a label by using the `InlineBlockNameProperties` options which can be set in `appsettings.json`:

```json
{
  "EPiServer": {
    "CmsUI": {
      "InlineBlockNameProperties": {
        "Contact": "Heading",
        "Teaser": "Heading"
      }
    }
  }
}
```

Or in `Startup.cs`

```csharp
services.Configure<InlineBlockNamePropertiesOptions>(options => {
  options.Add("Contact", "Heading");
  options.Add("Teaser", "Heading");
});
```

It is a `Dictionary\<string, string>` of `BlockTypeName / PropertyName`.

After adding those options the `ContentArea` looks like this:

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/X9pzMaQB71R4Vmy-ls5XO_c5316c3-image.png)

This is because you instructed the `ContentArea` editor to use `Heading` property as label for *Contact & Teaser* block types.

### Opt-in to inline blocks

In version 12.22.3, you can turn on the ability to create inline blocks from `ContentArea`  by using `UIOptions`.

```csharp
services.Configure<UIOptions>(uiOptions => {  
  uiOptions.InlineBlocksInContentAreaEnabled = true;
});
```

You also can opt-in from `appsettings.json`.

```json
{
  "EPiServer": {
    "CmsUI": {
      "UI": {
        "InlineBlocksInContentAreaEnabled": true
      }
    }
  }
}
```

After turning that flag on, the link to **Create a new block** creates blocks inline to the parent `ContentArea` property, potentially creating a version of the current content item.

### Create inline blocks programmatically

While inline blocks are typically created and managed through the Optimizely CMS editorial interface, there are scenarios where you want to create them programmatically. This section outlines how to create and assign inline blocks using C# code.

Remember that inline blocks are not standalone `IContent` instances. Instead, they are `BlockData` objects embedded directly within a property of a parent content item (for instance, a page or another block). Their lifecycle is tied to the parent content item.

### Prerequisites

For the following examples, assume you have the following content types defined in your project:

```csharp
using EPiServer.Core;
using EPiServer.DataAbstraction;
using EPiServer.DataAnnotations;
using EPiServer.Web; // For UIHint

namespace MyProject.Business.InlineBlocks
{
    // A simple block type intended for inline use
    [ContentType(DisplayName = "Simple Inline Block", GUID = "A1B2C3D4-E5F6-7890-1234-567890ABCDEF",
        Description = "A basic block for demonstrating inline creation.")]
    public class SimpleInlineBlock : BlockData
    {
        [Display(Name = "Title", Order = 10)]
        public virtual string Title { get; set; }

        [Display(Name = "Description", Order = 20)]
        public virtual string Description { get; set; }
    }

    // A page type that contains properties capable of holding inline blocks
    [ContentType(DisplayName = "Page With Inline Blocks", GUID = "B1C2D3E4-F5G6-7890-1234-567890ABCDEF",
        Description = "A page type to demonstrate programmatic inline block assignment.")]
    public class PageWithInlineBlocks : PageData
    {
        // A single property for an inline block (BlockData type)
        [Display(Name = "My Single Inline Block", Order = 100)]
        public virtual SimpleInlineBlock MySingleInlineBlock { get; set; }

        // A ContentArea property that can contain inline blocks or referenced blocks
        [Display(Name = "My Content Area", Order = 200)]
        public virtual ContentArea MyContentArea { get; set; }
    }
}
```

You will also need to inject `IContentRepository` and `IContentTypeRepository` into your service or class where you perform these operations.

```csharp
using EPiServer.Core;
using EPiServer.DataAbstraction;
using EPiServer.ServiceLocation; // For ServiceLocator.Current.GetInstance
using EPiServer.DataAccess; // For SaveAction
using System;
using System.Collections.Generic;

namespace MyProject.Business.InlineBlocks
{
    public class InlineBlockCreationExamples
    {
        private readonly IContentRepository _contentRepository;
        private readonly IContentTypeRepository _contentTypeRepository;

        public InlineBlockCreationExamples()
        {
            _contentRepository = ServiceLocator.Current.GetInstance<IContentRepository>();
            _contentTypeRepository = ServiceLocator.Current.GetInstance<IContentTypeRepository>();
        }

        // ... (Example methods below)
    }
}
```

### 1. Assign an inline block to a direct property

Use this method when a content type has a property explicitly defined as a `BlockData` type (for instance, `public virtual SimpleInlineBlock MySingleInlineBlock { get; set; }`).

```csharp
        /// <summary>
        /// Creates an instance of SimpleInlineBlock and assigns it to the 'MySingleInlineBlock'
        /// property of a 'PageWithInlineBlocks' page.
        /// </summary>
        /// <param name="parentPageLink">The ContentReference of the parent page.</param>
        public void CreateAndAssignSingleInlineBlock(ContentReference parentPageLink)
        {
            // 1. Retrieve the existing parent page in writable mode
            var page = _contentRepository.Get<PageWithInlineBlocks>(parentPageLink).CreateWritableClone() as PageWithInlineBlocks;
            if (page == null)
            {
                Console.WriteLine($"Error: Parent page with ID {parentPageLink.ID} not found or not of type PageWithInlineBlocks.");
                return;
            }

            // 2. Instantiate your inline block type
            var newInlineBlock = new SimpleInlineBlock
            {
                Title = "Programmatically Created Title",
                Description = "This is a description for an inline block created via code."
            };

            // 3. Assign the inline block instance directly to the property on the parent page
            page.MySingleInlineBlock = newInlineBlock;

            // 4. Save the parent page. This action automatically saves the inline block along with the page.
            _contentRepository.Save(page, SaveAction.Publish, EPiServer.Security.AccessLevel.Publish);

            Console.WriteLine($"Successfully created and assigned SimpleInlineBlock to page '{page.Name}' (ID: {page.ContentLink.ID}).");
        }
```

### 2. Add an inline block to a `ContentArea` property

`ContentArea` properties can hold both referenced blocks (standalone `IContent` items) and inline blocks. To add an inline block, you create a `ContentAreaItem` where the `Content` property holds the `BlockData` instance, and `ContentLink` is left `null`.

The following example creates an instance of `SimpleInlineBlock` and adds it as an inline block to the `MyContentArea` property of a `PageWithInlineBlocks` page.

```csharp
        /// <param name="parentPageLink">The ContentReference of the parent page.</param>
        public void AddInlineBlockToContentArea(ContentReference parentPageLink)
        {
            // 1. Retrieve the existing parent page in writable mode
            var page = _contentRepository.Get<PageWithInlineBlocks>(parentPageLink).CreateWritableClone() as PageWithInlineBlocks;
            if (page == null)
            {
                Console.WriteLine($"Error: Parent page with ID {parentPageLink.ID} not found or not of type PageWithInlineBlocks.");
                return;
            }

            // 2. Ensure the ContentArea exists and is initialized
            if (page.MyContentArea == null)
            {
                page.MyContentArea = new ContentArea();
            }

            // 3. Instantiate your inline block type
            var newInlineBlock = new SimpleInlineBlock
            {
                Title = "ContentArea Inline Block Title",
                Description = "This block was added to a ContentArea programmatically."
            };

            // 4. Create a ContentAreaItem for the inline block.
            //    For inline blocks, assign the BlockData instance to the 'Content' property.
            //    The 'ContentLink' property remains null.
            var contentAreaItem = new ContentAreaItem
            {
                Content = newInlineBlock,
                // Optionally, you can set a DisplayOption if your site uses them
                // DisplayOption = "FullWidth"
            };

            // 5. Add the new ContentAreaItem to the ContentArea's existing items
            var contentAreaItems = new List<ContentAreaItem>(page.MyContentArea.Items ?? new List<ContentAreaItem>());
            contentAreaItems.Add(contentAreaItem);
            page.MyContentArea.Items = contentAreaItems;

            // 6. Save the parent page. This action saves the ContentArea and its embedded inline block.
            _contentRepository.Save(page, SaveAction.Publish, EPiServer.Security.AccessLevel.Publish);

            Console.WriteLine($"Successfully added SimpleInlineBlock to ContentArea of page '{page.Name}' (ID: {page.ContentLink.ID}).");
        }
```

### 3. Distinguishing from referenced blocks in `ContentArea`

It is crucial to understand the difference between adding an *inline block* to a `ContentArea` and adding a *reference to a standalone block*.

- **Inline block** – The `BlockData` instance is embedded directly within the `ContentAreaItem.Content` property. It has no `ContentLink` and no independent existence in the content tree.
- **Referenced block** – The `ContentAreaItem.ContentLink` property points to an existing `IContent` block that lives independently in the content tree.

The following example demonstrates how to add a reference to an existing standalone block to a `ContentArea` property. This is NOT an inline block.

```csharp
        /// <param name="parentPageLink">The ContentReference of the parent page.</param>
        /// <param name="existingBlockLink">The ContentReference of an already existing standalone block.</param>
        public void AddExistingBlockReferenceToContentArea(ContentReference parentPageLink, ContentReference existingBlockLink)
        {
            // 1. Retrieve the existing parent page in writable mode
            var page = _contentRepository.Get<PageWithInlineBlocks>(parentPageLink).CreateWritableClone() as PageWithInlineBlocks;
            if (page == null)
            {
                Console.WriteLine($"Error: Parent page with ID {parentPageLink.ID} not found or not of type PageWithInlineBlocks.");
                return;
            }

            // 2. Ensure the ContentArea exists and is initialized
            if (page.MyContentArea == null)
            {
                page.MyContentArea = new ContentArea();
            }

            // 3. Create a ContentAreaItem referencing the existing standalone block.
            //    Assign the ContentReference to the 'ContentLink' property.
            var contentAreaItem = new ContentAreaItem
            {
                ContentLink = existingBlockLink, // Reference to the standalone block
                // Optionally, you can set a DisplayOption
                // DisplayOption = "HalfWidth"
            };

            // 4. Add the new ContentAreaItem to the ContentArea's existing items
            var contentAreaItems = new List<ContentAreaItem>(page.MyContentArea.Items ?? new List<ContentAreaItem>());
            contentAreaItems.Add(contentAreaItem);
            page.MyContentArea.Items = contentAreaItems;

            // 5. Save the parent page.
            _contentRepository.Save(page, SaveAction.Publish, EPiServer.Security.AccessLevel.Publish);

            Console.WriteLine($"Successfully added reference to existing block (ID: {existingBlockLink.ID}) to ContentArea of page '{page.Name}' (ID: {page.ContentLink.ID}).");
        }
```

### Manage multilingual sites with inline blocks

Understanding how inline blocks interact with translations and `[CultureSpecific]` properties helps you to manage multilingual sites. Since inline blocks are stored directly within their parent content item and are not separate `IContent` instances, their globalization behavior is intrinsically linked to the parent.

- **Translations**
  - Properties within an inline block are translated as part of the parent content item. When you create a new language version of a page or block that contains an inline block, the inline block's properties will also be duplicated for translation in that new language version.
  - There is no separate publishing or approval workflow for inline blocks across different languages; their lifecycle is entirely managed through the parent content item.
  - Editors translate the inline block's properties directly within the context of the parent content item's language version.
- `[CultureSpecific]` **properties**
  - The `[CultureSpecific]` attribute functions for properties defined within an inline block.
  - If a property inside an inline block is marked with `[CultureSpecific]`, its value can be unique for each language version of the *parent* content item. Changes to this property in one language will not affect other language versions.
  - If a property inside an inline block is *not* marked with `[CultureSpecific]`, its value will be shared across all language versions of the parent content item. A change to this property in one language will propagate to all other language versions. This is important to consider for properties like images, IDs, or configuration settings that might be universal across cultures.

Consider a `HeroBlock` used as an inline block within a `StandardPage`.

```csharp
// HeroBlock.cs
[ContentType(DisplayName = "Hero Block", GUID = "...", Description = "")]
public class HeroBlock : BlockData
{
    [CultureSpecific]
    [Display(Name = "Headline", Order = 10)]
    public virtual string Headline { get; set; }

    [Display(Name = "Background Image", Order = 20)]
    [UIHint(UIHint.Image)]
    public virtual ContentReference BackgroundImage { get; set; }
}
```

- If `StandardPage` has English and Swedish versions:
  - The `Headline` property of the `HeroBlock` can have different values for the English and Swedish versions of the `StandardPage` because it is `[CultureSpecific]`.
  - The `BackgroundImage` property of the `HeroBlock` will be the same for both English and Swedish versions of the `StandardPage` because it is *not* `[CultureSpecific]`. If an editor changes the `BackgroundImage` on the English page, the Swedish page will also show the new image.

## CMS UI 12.20.0 and earlier

The inline edit dialog box is designed to be simple while letting editors edit a block's most common properties.

![](https://api.archbee.com/api/optimize/BrbvVORKJ5iIeSMZye5kI/CRKSSfX6c5wbp9NVamYJ__f6041c6-small-blockquickeditview.png)

Optimizely introduced the `InlineBlockEditSettings` configuration attribute so that you can apply it to your block content type and hide or show the `Name` and `Categories` properties. You can also use this attribute to hide specific groups to make the editing form cleaner.

The attribute contains three properties:

| Property               | Default value | Description                                           |
| ---------------------- | ------------- | ----------------------------------------------------- |
| `ShowNameProperty`     | false         | When true, then the Name property is displayed.       |
| `ShowCategoryProperty` | false         | When true, then the Categories property is displayed. |
| `HiddenGroups`         | Advanced      | Comma-separated list of tabs that should be hidden.   |

:::hint{type="info"}
**Note**
Advanced group is the **Settings** tab in the user interface, which is hidden by default in the inline edit dialog box.
:::

### Change settings for a specific block content type

To turn on the `Name` property for a specific block content type:

```csharp
[SiteContentType(GUID = "67F617A4-2175-4360-975E-75EDF2B924A7",
  GroupName = SystemTabNames.Content)]
[SiteImageUrl]
[InlineBlockEditSettings(ShowNameProperty = true)]
public class EditorialBlock: SiteBlockData {
  [Display(GroupName = SystemTabNames.Content)]
  [CultureSpecific]
  public virtual XhtmlString MainBody {
    get;
    set;
  }
}
```

Below is to display the `Name` and `Categories` properties and `Settings` group:

```csharp
[SiteContentType(GUID = "9E7F6DF5-A963-40C4-8683-211C4FA48AE1")]
[SiteImageUrl]
[InlineBlockEditSettings(ShowNameProperty = true, ShowCategoryProperty = true, HiddenGroups = "")]
public class AdvancedBlock: SiteBlockData {
  [Display(Order = 1, GroupName = SystemTabNames.Content)]
  public virtual string Text1 {
    get;
    set;
  }

  [Display(Order = 2, GroupName = SystemTabNames.Content)]
  public virtual string Text2 {
    get;
    set;
  }

  [Display(Order = 1, GroupName = Global.GroupNames.Products)]
  public virtual string Text3 {
    get;
    set;
  }

  [Display(Order = 2, GroupName = Global.GroupNames.Products)]
  public virtual string Text4 {
    get;
    set;
  }
}
```

To hide more than one group:

```csharp
[SiteContentType(GUID = "9E7F6DF5-A963-40C4-8683-211C4FA48AE1")]
[SiteImageUrl]
[InlineBlockEditSettings(HiddenGroups = "Advanced, Contact")]
public class AdvancedBlock: SiteBlockData {
  [Display(Order = 1, GroupName = SystemTabNames.Content)]
  public virtual string Text1 {
    get;
    set;
  }

  [Display(Order = 2, GroupName = SystemTabNames.Content)]
  public virtual string Text2 {
    get;
    set;
  }

  [Display(Order = 1, GroupName = Global.GroupNames.Products)]
  public virtual string Text3 {
    get;
    set;
  }

  [Display(Order = 2, GroupName = Global.GroupNames.Contact)]
  public virtual string Text4 {
    get;
    set;
  }
}
```

### Change settings for multiple block content types

If you want to show `Name` for several block content types, you can configure the setting in their base class, like this:

```csharp
[InlineBlockEditSettings(ShowNameProperty = true)]
public abstract class SiteBlockData: EPiServer.Core.BlockData {}

[SiteContentType(GUID = "9E7F6DF5-A963-40C4-8683-211C4FA48AE1")]
[SiteImageUrl]
public class AdvancedBlock: SiteBlockData {
  [Display(Order = 1, GroupName = SystemTabNames.Content)]
  public virtual string Text1 {
    get;
    set;
  }

  [Display(Order = 2, GroupName = SystemTabNames.Content)]
  public virtual string Text2 {
    get;
    set;
  }

  [Display(Order = 1, GroupName = Global.GroupNames.Products)]
  public virtual string Text3 {
    get;
    set;
  }

  [Display(Order = 2, GroupName = Global.GroupNames.Contact)]
  public virtual string Text4 {
    get;
    set;
  }
}
```

:::hint{type="info"}
**Note**
If you want to change a setting in a child block type, while still wanting to have some other settings from the base class, you have to copy those settings to the child block type class because the settings in the child block type override the settings in the base class.
:::

## Override auto-generated name for inline-creating blocks

Because the `Name` property is hidden by default, blocks created from an inline edit dialog (inline create) get an automatically generated name. The name is generated using `ILocalAssetNameGenerator`, and the default format is `PageName BlockType AutoIncrementId`.

To override the default auto-generated name format, you just need to implement `ILocalAssetNameGenerator`.
