New to Telerik UI for Blazor? Start a free 30-day trial
In-Place Editor Component
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
InPlaceEditor
is a generic component. It supports strings and most value types, including nullable types.- Initially, the component renders a clickable Button with
Clear
FillMode
that shows the currentValue
. - The component detects the type of its
Value
and renders the appropriate Telerik editor:- CheckBox for
bool
- DatePicker for
DateTime
andDateOnly
- NumericTextBox for
int
,double
,decimal
, and the other numeric types - TextBox for
string
- TimePicker for
TimeOnly
- CheckBox for
- If the
Width
parameter is not set, the In-Place Editor approximately matches the width of its editor components to the currentValue
length. The component uses amonospace
font-family
to make this easier. - The component features a
ReadOnly
mode that controls the editability, for example, depending on user permissions. - The
DisplayFormat
parameter affects theValue
consistently in both read mode and edit mode. - The
Placeholder
parameter provides a helper label that will show when theValue
isnull
or empty. - The
ShowIcons
parameter controls the visibility of optional SVG Icons. The icons hint users about the ability to edit the componentValue
or 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.razor
and all.razor
files that useInPlaceEditor
. - The
Class
parameter allows you to apply custom styles. - The
Title
parameter allows you to show a tooltip hint on read mode. - To see invalid state styling and validation messages in Forms, pass the respective
ValueExpression
values to theInPlaceEditor
component. InPlaceEditor.razor.css
is a CSS isolation file. It depends on aYourAppName.styles.css
file inApp.razor
to load.
Example
The features and business logic below can be subject to additional customizations and enhancements.
To run the code successfully:
- Replace
YourAppName
with the actual root namespace of your app. - Make sure your app supports CSS isolation and loads a
YourAppName.styles.css
file. 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; }
}
}