Tag Collection Components

Tag collection components display and manage a collection of short labeled items rendered as chips. TagCollectionPropertyEdit lets users add new tags via an autocomplete input and remove existing ones with a chip delete button. TagCollectionPropertyView renders the same collection read-only. Both components are auto-selected by PropertyComponent when the property's data type is "Tags" — no manual component selection is needed.

TagCollectionItem

Each tag in the collection is represented at the UI layer as a TagCollectionItem record:

public sealed record TagCollectionItem(Guid? Guid, string Name);
Field Type Description
Guid Guid? The entity GUID of the underlying tag entity. null when constructing a new tag before it has been persisted.
Name string The display label rendered on the chip. Corresponds to the Name property on the server-side tag entity.

Guid and Name are distinct because the server entity may carry additional state (e.g., a canonical Value used in business logic) that differs from the user-visible label. In a plain tag model where no such distinction exists, Guid uniquely identifies the row while Name is the only visible text.

How Tags Are Stored

Tag collections are modeled as a navigation collection on the server entity — a one-to-many relationship to a tag entity that owns a Name property. At the UI layer the collection is accessed through IDataSetCollection, the same abstraction used for all collection properties. TagCollectionPropertyEdit calls AddAsync when the user confirms a new tag and RemoveAsync when the user deletes a chip. Changes propagate through the standard DataSet change pipeline and are saved via the normal save operation on the parent entity.

No special storage API is needed on the consuming page — the component handles all IDataSetCollection operations internally.

Auto-Selection

The registration in DefaultDynamicComponentRegistrations maps the data type "Tags" to the tag components:

Data Type Edit Component View Component
Tags TagCollectionPropertyEdit TagCollectionPropertyView

When a property is declared with data type "Tags" in the server graph, PropertyComponent resolves the correct component automatically:

<PropertyComponent Path="Tags" />

No DisplayMode override or ChildContent is required for standard tag rendering.

TagCollectionPropertyView

TagCollectionPropertyView renders the tag collection as a horizontal, wrapping row of read-only chips. Each chip displays the tag's Name. There is no interaction — chips cannot be deleted and no input is shown.

CSS classes applied to the container: tag-collection tag-collection-view.

Use this component (or let PropertyComponent select it) when the enclosing DataGraph is in DisplayMode.View:

<DataGraph Builder="@BuildGraph" DataSet="@_dataSet" EntityGuid="@guid" DisplayMode="DisplayMode.View">
    <PropertyComponent Path="Tags" />
</DataGraph>

TagCollectionPropertyEdit

TagCollectionPropertyEdit renders an interactive chip group. Its behavior depends on whether the property context is read-only at runtime (PropertyContext.IsReadOnly()):

When editable:

  • Existing tags are rendered as deletable chips. Clicking the X on a chip calls RemoveAsync on the underlying IDataSetCollection.
  • An "Add Tag" chip with a dashed border is shown after the existing tags. Clicking it reveals an autocomplete input.
  • The autocomplete searches existing tags server-side as the user types (200 ms debounce). If the entered text does not match an existing option, a "Create" option is shown inline.
  • Selecting an option or choosing the create option calls AddAsync on the collection.
  • Pressing Escape or clicking the X button next to the input dismisses it without adding a tag.
  • All mutating actions are disabled while a server operation is in progress (IsLoading).

When read-only at runtime (property marked read-only by the server's RecordReadOnly, even inside an edit-mode DataGraph):

  • Chips are rendered without a delete button, matching the appearance of TagCollectionPropertyView.
  • The "Add Tag" input is not shown.

CSS classes applied to the container: tag-collection tag-collection-edit.

Code Examples

Rendering a tag property in edit mode

Declare the property in the server-side graph with data type "Tags", then place a PropertyComponent inside a DataGraph in edit mode. The framework selects TagCollectionPropertyEdit automatically.

<DataGraph Builder="@BuildGraph" DataSet="@_dataSet" EntityGuid="@guid" DisplayMode="DisplayMode.Edit">
    <PropertyComponent Path="Tags" />
</DataGraph>

Rendering a tag property in view mode

Switch the DataGraph to DisplayMode.View. The framework selects TagCollectionPropertyView automatically.

<DataGraph Builder="@BuildGraph" DataSet="@_dataSet" EntityGuid="@guid" DisplayMode="DisplayMode.View">
    <PropertyComponent Path="Tags" />
</DataGraph>

You can also force view mode for a single property while the rest of the graph remains editable:

<DataGraph Builder="@BuildGraph" DataSet="@_dataSet" EntityGuid="@guid" DisplayMode="DisplayMode.Edit">
    <PropertyComponent Path="Name" />
    <PropertyComponent Path="Tags" DisplayMode="DisplayMode.View" />
</DataGraph>

Reading the current tag values for conditional logic

If page logic needs to inspect the current tag values — for example to show or hide another field — read the collection from the DataSet directly and project it to TagCollectionItem the same way the base component does:

var collection = _dataSet.GetCollection("Tags", tagsPropertyType);
var currentTags = collection
    .Select(item => item.Get<string>("Name") ?? string.Empty)
    .Where(name => !string.IsNullOrWhiteSpace(name))
    .ToList();

bool hasPriorityTag = currentTags.Contains("Priority");

GetCollection returns an IDataSetCollection. Iterate its items and call Get<T>("Name") to read each tag's label without taking a dependency on TagCollectionItem directly.