New to Telerik UI for Blazor? Start a free 30-day trial
In-Place Editor Component
Updated over 6 months ago
Environment
| Product | UI for Blazor |
Description
This KB article demonstrates and describes how to create a custom InPlaceEditor component. The article also answers the following questions:
- How to create an in-place editor, which looks like text when in read mode and switches to an input component when editable?
- How to toggle between text content and an editor to allow users to edit something in place?
Solution
The sample below uses an algorithm which toggles between read-only UI and an editable component on user click and blur.
How It Works
InPlaceEditoris a generic component. It supports strings and most value types, including nullable types.- Initially, the component renders a clickable Button with
ClearFillModethat shows the currentValue. - The component detects the type of its
Valueand renders the appropriate Telerik editor:- CheckBox for
bool - DatePicker for
DateTimeandDateOnly - NumericTextBox for
int,double,decimal, and the other numeric types - TextBox for
string - TimePicker for
TimeOnly
- CheckBox for
- If the
Widthparameter is not set, the In-Place Editor approximately matches the width of its editor components to the currentValuelength. The component uses amonospacefont-familyto make this easier. - The component features a
ReadOnlymode that controls the editability, for example, depending on user permissions. - The
DisplayFormatparameter affects theValueconsistently in both read mode and edit mode. - The
Placeholderparameter provides a helper label that will show when theValueisnullor empty. - The
ShowIconsparameter controls the visibility of optional SVG Icons. The icons hint users about the ability to edit the componentValueor provide clickable Save and Cancel commands in edit mode. The parameter is of typeInPlaceEditorShowIcons, which is a custom enum and must be imported in bothInPlaceEditor.razorand all.razorfiles that useInPlaceEditor. - The
Classparameter allows you to apply custom styles. - The
Titleparameter allows you to show a tooltip hint on read mode. - To see invalid state styling and validation messages in Forms, pass the respective
ValueExpressionvalues to theInPlaceEditorcomponent. InPlaceEditor.razor.cssis a CSS isolation file. It depends on aYourAppName.styles.cssfile inApp.razorto load.
Example
The features and business logic below can be subject to additional customizations and enhancements.
To run the code successfully:
- Replace
YourAppNamewith the actual root namespace of your app. - Make sure your app supports CSS isolation and loads a
YourAppName.styles.cssfile. Browser caching of this file can prevent the InPlaceEditor styles from showing.
RAZOR
@* import InPlaceEditorType enum *@
@using YourAppName.Models
@using System.ComponentModel.DataAnnotations
<h1>InPlaceEditor Component</h1>
<p>
This in-place editor component works with strings and value types, including nullables, for example:
<InPlaceEditor @bind-Value="@NumericValue"
DisplayFormat="C2"
Placeholder="Enter Number..." />
The component supports custom styles and responsive textbox width that depends on the value:
<InPlaceEditor @bind-Value="@StringValue"
Class="primary-color"
ShowIcons="@InPlaceEditorShowIcons.Hover" />
The icon can be visible only on hover:
<InPlaceEditor @bind-Value="@DateValue"
Class="primary-color"
DisplayFormat="d"
ShowIcons="@InPlaceEditorShowIcons.Hover" />
(unless the value is empty) or never:
<InPlaceEditor @bind-Value="@TimeValue"
Class="primary-color"
DisplayFormat="HH:mm"
ShowIcons="@InPlaceEditorShowIcons.Never" />
You can even edit booleans:
<InPlaceEditor @bind-Value="@BoolValue"
Class="primary-color" />
</p>
<h2>Configuration</h2>
<ul>
<li>
<label for="editor-placeholder">Placeholder: </label>
<TelerikTextBox @bind-Value="@InPlaceEditorPlaceholder"
Id="editor-placeholder"
ShowClearButton="true"
Width="180px" />
</li>
<li><label><TelerikCheckBox @bind-Value="@InPlaceEditorReadOnly" /> Read Only</label></li>
<li>
<span>Show Icon: </span>
<TelerikButtonGroup SelectionMode="@ButtonGroupSelectionMode.Single">
<ButtonGroupToggleButton Selected="@( InPlaceEditorShowIcons == InPlaceEditorShowIcons.Always )"
OnClick="@( () => InPlaceEditorShowIcons = InPlaceEditorShowIcons.Always )">
Always
</ButtonGroupToggleButton>
<ButtonGroupToggleButton Selected="@( InPlaceEditorShowIcons == InPlaceEditorShowIcons.Hover )"
OnClick="@( () => InPlaceEditorShowIcons = InPlaceEditorShowIcons.Hover )">
Hover
</ButtonGroupToggleButton>
<ButtonGroupToggleButton Selected="@( InPlaceEditorShowIcons == InPlaceEditorShowIcons.Never )"
OnClick="@( () => InPlaceEditorShowIcons = InPlaceEditorShowIcons.Never )">
Never
</ButtonGroupToggleButton>
</TelerikButtonGroup>
</li>
<li>
<label for="editor-title">Title: </label>
<TelerikTextBox @bind-Value="@InPlaceEditorTitle"
Id="editor-title"
ShowClearButton="true"
Width="180px" />
</li>
<li>
<label for="editor-width">Editor Width: </label>
<TelerikNumericTextBox @bind-Value="@InPlaceEditorWidth"
Format="# px"
Id="editor-width"
Width="120px" />
</li>
</ul>
<p>
In Place Editor:
<InPlaceEditor @bind-Value="@InPlaceEditorValue"
Class="primary-color"
Placeholder="@InPlaceEditorPlaceholder"
ReadOnly="@InPlaceEditorReadOnly"
ShowIcons="@InPlaceEditorShowIcons"
Title="@InPlaceEditorTitle"
Width="@( InPlaceEditorWidth.HasValue ? $"{InPlaceEditorWidth}px" : null )" />
</p>
<h2>Form Validation</h2>
<TelerikForm Model="@Employee">
<FormValidation>
<DataAnnotationsValidator />
</FormValidation>
<FormItems>
<FormItem Field="@nameof(Person.Name)">
<Template>
Name:
<InPlaceEditor Value="@Employee.Name"
ValueChanged="@( (string newValue) => Employee.Name = newValue )"
ValueExpression="@( () => Employee.Name )"
Placeholder="Enter Name..." />
<TelerikValidationMessage For="@( () => Employee.Name )" />
</Template>
</FormItem>
<FormItem Field="@nameof(Person.BirthDate)">
<Template>
Hire Date:
<InPlaceEditor Value="@Employee.BirthDate"
ValueChanged="@( (DateTime? newValue) => Employee.BirthDate = newValue )"
ValueExpression="@( () => Employee.BirthDate )"
DisplayFormat="d"
Placeholder="Enter Date..."
T="@(DateTime?)" />
<TelerikValidationMessage For="@( () => Employee.BirthDate )" />
</Template>
</FormItem>
</FormItems>
</TelerikForm>
<style>
h1 {
font-size: 1.5rem;
}
h2 {
font-size: 1.2rem;
}
.primary-color {
color: var(--kendo-color-primary);
}
</style>
@code {
private bool BoolValue { get; set; }
private DateTime? DateValue { get; set; } = DateTime.Now;
private decimal? NumericValue { get; set; } = 1.23m;
private string StringValue { get; set; } = "foo bar";
private TimeOnly TimeValue { get; set; } = TimeOnly.FromDateTime(DateTime.Now);
private string InPlaceEditorPlaceholder { get; set; } = "Enter Value...";
private bool InPlaceEditorReadOnly { get; set; }
private InPlaceEditorShowIcons InPlaceEditorShowIcons { get; set; } = InPlaceEditorShowIcons.Always;
private string InPlaceEditorTitle { get; set; } = "Edit Sample Value";
private string InPlaceEditorValue { get; set; } = "foo bar";
private int? InPlaceEditorWidth { get; set; } = 120;
private Person Employee { get; set; } = new();
public class Person
{
[Required]
public string? Name { get; set; } = string.Empty;
[Required]
public DateTime? BirthDate { get; set; }
}
}