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
RemoveAsyncon the underlyingIDataSetCollection. - 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
AddAsyncon 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.