Field
Easily create form fields with labels, help text and input controls.
<sa-field-group>
<sa-field-set>
<sa-field-legend>Payment Method</sa-field-legend>
<sa-field-description>
All transactions are secure and encrypted
</sa-field-description>
<sa-field-group>
<sa-field>
<sa-field-label for="card-name">
Name on Card
</sa-field-label>
<sa-input
id="card-name"
placeholder="Ibn Battuta"
/>
</sa-field>
<sa-field>
<sa-field-label for="card-number">
Card Number
</sa-field-label>
<sa-input
id="card-number"
placeholder="1234 5678 9012 3456"
/>
<sa-field-description>
Enter your 16-digit card number
</sa-field-description>
</sa-field>
<div class="grid grid-cols-3 gap-4">
<sa-field>
<sa-field-label for="exp-month">
Month
</sa-field-label>
<sa-select id="exp-month">
<option value="01">01</option>
<option value="02">02</option>
<option value="03">03</option>
<option value="04">04</option>
<option value="05">05</option>
<option value="06">06</option>
<option value="07">07</option>
<option value="08">08</option>
<option value="09">09</option>
<option value="10">10</option>
<option value="11">11</option>
<option value="12">12</option>
</sa-select>
</sa-field>
<sa-field>
<sa-field-label for="exp-year">
Year
</sa-field-label>
<sa-select id="exp-year">
<option value="2024">2024</option>
<option value="2025">2025</option>
<option value="2026">2026</option>
<option value="2027">2027</option>
<option value="2028">2028</option>
<option value="2029">2029</option>
</sa-select>
</sa-field>
<sa-field>
<sa-field-label for="cvv">CVV</sa-field-label>
<sa-input id="cvv" placeholder="123"/>
</sa-field>
</div>
</sa-field-group>
</sa-field-set>
<sa-field-separator/>
<sa-field-set>
<sa-field-legend>Billing Address</sa-field-legend>
<sa-field-description>
The billing address associated with your payment method
</sa-field-description>
<sa-field-group>
<sa-field orientation="Horizontal">
<sa-input
type="checkbox"
id="same-as-shipping"
/>
<sa-field-label
for="same-as-shipping"
class="font-normal"
>
Same as shipping address
</sa-field-label>
</sa-field>
</sa-field-group>
</sa-field-set>
<sa-field-set>
<sa-field-group>
<sa-field>
<sa-field-label for="optional-comments">
Comments
</sa-field-label>
<sa-textarea
id="optional-comments"
placeholder="Add any additional comments"
class="resize-none"
/>
</sa-field>
</sa-field-group>
</sa-field-set>
<sa-field orientation="Horizontal">
<sa-button type="button">Submit</sa-button>
<sa-button variant="Outline" type="button">
Cancel
</sa-button>
</sa-field>
</sa-field-group>Usage
The <sa-field> family of Tag Helpers are designed for composing accessible forms. <sa-field> is the core wrapper for a single field.
<sa-field>
<sa-field-label for="input-id">Label</sa-field-label>
<!-- We use sa-input below, but can be any StellarAdmin input such as sa-select, sa-textarea, etc. -->
<sa-input id="input-id" />
<sa-field-description>Optional helper text</sa-field-description>
<sa-field-error>Validation message</sa-field-error>
</sa-field><sa-field-content> is a flex column that groups label and description. This component is useful when you use a field in horizontal orientation
<sa-field orientation="Horizontal">
<sa-input id="input-id" type="checkbox"/>
<sa-field-content>
<sa-field-label for="input-id">
Sync Desktop & Documents folders
</sa-field-label>
<sa-field-description>
Your Desktop & Documents folders are being synced with iCloud Drive. You can access them from other
devices.
</sa-field-description>
</sa-field-content>
</sa-field>Wrap related fields with <sa-field-group>, and use <sa-field-set> with <sa-field-legend> for semantic grouping.
<sa-field-set>
<sa-field-legend>Payment Method</sa-field-legend>
<sa-field-description>
All transactions are secure and encrypted
</sa-field-description>
<sa-field-group>
<sa-field>
<sa-field-label for="card-name">
Name on Card
</sa-field-label>
<sa-input
id="card-name"
placeholder="Ibn Battuta"
/>
</sa-field>
<sa-field>
<sa-field-label for="card-number">
Card Number
</sa-field-label>
<sa-input
id="card-number"
placeholder="1234 5678 9012 3456"
/>
<sa-field-description>
Enter your 16-digit card number
</sa-field-description>
</sa-field>
</sa-field-group>
</sa-field-set>Explicit and implicit fields
The usage examples demonstrated so far require a lot of boilerplate when creating fields by specifying <sa-field>, <sa-field-label>, <sa-field-description>, etc. To improve the developer experience, all the StellarAdmin input controls such as <sa-input>, <sa-select>, <sa-textarea>, etc. can implicitly create fields using one of the following two techniques.
-
When using data binding (with the
asp-forattribute), StellarAdmin will implicitly wrap the input inside a<sa-field>with the corresponding<sa-field-label>and<sa-field-description>inferred from data annotations. If your model contains errors related to the bound property, a<sa-field-error>component with the error message will also be added.<sa-input asp-for="Model.Name"/> -
If you are not using data binding, you can also opt in to implicit fields by specifying any combination of the
label,description, anderrorattributes. When doing this, your input will be wrapped inside a<sa-field>with the corresponding<sa-field-label>,<sa-field-description>, and<sa-field-error>automatically added.<sa-input label="First Name" description="First name as displayed on card" error="This is a super-dooper error"/>
In both cases mentioned above, you can opt out of implicit fields by setting the render-field attribute to false. In the example below, StellarAdmin will not create an implicit field, even though we're using model binding.
<sa-input render-field="false" asp-for="Model.Name"/>Most of the examples in this document demonstrate both explicit and implicit mode. Notice how compact the implicit examples are compared to their explicit counterparts.
Examples
Implicit fields
Whenever you use any if the various field input Tag Helpers (such as <sa-input>, <sa-textarea>, <sa-select> etc.) along with data binding, StellarAdmin will implicitly create a field with a label, description, and placeholder for you. You can see this demonstrated in the example below which implements the same form as above, but using data binding.
@{
var months = Enumerable.Range(1, 12).Select(i => $"{i:00}").Select(i => new SelectListItem(i, i));
var years = Enumerable.Range(2024, 2029).Select(i => new SelectListItem(i.ToString(), i.ToString()));
}
<sa-field-group>
<sa-field-set>
<sa-field-legend>Payment Method</sa-field-legend>
<sa-field-description>
All transactions are secure and encrypted
</sa-field-description>
<sa-field-group>
<sa-input asp-for="Model.Name"/>
<sa-input asp-for="Model.CardNumber"/>
<div class="grid grid-cols-3 gap-4">
<sa-select asp-for="Model.Month" asp-items="@months" />
<sa-select asp-for="Model.Year" asp-items="@years" />
<sa-input asp-for="Model.Cvv"/>
</div>
</sa-field-group>
</sa-field-set>
<sa-field-separator/>
<sa-field-set>
<sa-field-legend>Billing Address</sa-field-legend>
<sa-field-description>
The billing address associated with your payment method
</sa-field-description>
<sa-field-group>
<sa-input asp-for="Model.IsBillingAddressSame" />
</sa-field-group>
</sa-field-set>
<sa-field-set>
<sa-field-group>
<sa-textarea asp-for="Model.Comments"/>
</sa-field-group>
</sa-field-set>
<sa-field orientation="Horizontal">
<sa-button type="button">Submit</sa-button>
<sa-button variant="Outline" type="button">
Cancel
</sa-button>
</sa-field>
</sa-field-group>public class ImplicitModel
{
[Display(
Name = "Card Number",
Description = "Enter your 16-digit card number",
Prompt = "1234 5678 9012 3456"
)]
public string? CardNumber { get; set; }
[Display(Name = "Comments", Prompt = "Add any additional comments")]
public string? Comments { get; set; }
[Display(Name = "CVV")]
public string? Cvv { get; set; }
[Display(Name = "Same as shipping address")]
public bool IsBillingAddressSame { get; set; }
public string? Month { get; set; }
[Display(Name = "Name on Card", Prompt = "Ibn Battuta")]
public string? Name { get; set; }
public string? Year { get; set; }
}Input
<sa-field-set>
<sa-field-group>
<sa-field>
<sa-field-label for="email">Email</sa-field-label>
<sa-input id="email" type="text" placeholder="e.g. ibn.battuta@rihlah.travel"/>
<sa-field-description>Your email address</sa-field-description>
</sa-field>
<sa-field>
<sa-field-label for="password">Password</sa-field-label>
<sa-input id="password" type="password" placeholder="••••••••"/>
<sa-field-description>
Must be at least 8 characters long.
</sa-field-description>
</sa-field>
</sa-field-group>
</sa-field-set><sa-field-set>
<sa-field-group>
<sa-input asp-for="Model.Email"/>
<sa-input asp-for="Model.Password"/>
</sa-field-group>
</sa-field-set>public class InputImplicitModel
{
[Display(
Name = "Email",
Description = "Your email address",
Prompt = "e.g. ibn.battuta@rihlah.travel"
)]
[DataType(DataType.EmailAddress)]
public string? Email { get; set; }
[Display(
Name = "Password",
Description = "Must be at least 8 characters long.",
Prompt = "••••••••"
)]
[DataType(DataType.Password)]
public string Password { get; set; }
}Textarea
<sa-field>
<sa-field-label for="feedback">Feedback</sa-field-label>
<sa-textarea
id="feedback"
placeholder="Your feedback helps us improve..."
rows="4"/>
<sa-field-description>
Share your thoughts about our service.
</sa-field-description>
</sa-field><sa-textarea asp-for="Model.Feedback" rows="4"/>public class TextareaImplicitModel
{
[Display(
Name = "Feedback",
Description = "Share your thoughts about our service.",
Prompt = "Your feedback helps us improve..."
)]
public string? Feedback { get; set; }
}Select
<sa-field>
<sa-field-label>Department</sa-field-label>
<sa-select>
<option value="engineering">Engineering</option>
<option value="design">Design</option>
<option value="marketing">Marketing</option>
<option value="sales">Sales</option>
<option value="support">Customer Support</option>
<option value="hr">Human Resources</option>
<option value="finance">Finance</option>
<option value="operations">Operations</option>
</sa-select>
<sa-field-description>
Select your department or area of work.
</sa-field-description>
</sa-field><sa-select asp-for="Model.Department">
<option value="engineering">Engineering</option>
<option value="design">Design</option>
<option value="marketing">Marketing</option>
<option value="sales">Sales</option>
<option value="support">Customer Support</option>
<option value="hr">Human Resources</option>
<option value="finance">Finance</option>
<option value="operations">Operations</option>
</sa-select>public class SelectImplicitModel
{
[Display(Name = "Department", Description = "Select your department or area of work.")]
public string? Department { get; set; }
}Checkbox
<sa-field-group>
<sa-field-set>
<sa-field-legend variant="Label">
Show these items on the desktop
</sa-field-legend>
<sa-field-description>
Select the items you want to show on the desktop.
</sa-field-description>
<sa-field-group class="gap-3">
<sa-field orientation="Horizontal">
<sa-input type="checkbox" id="finder-pref-hard-disks"/>
<sa-field-label
for="finder-pref-hard-disks"
class="font-normal">
Hard disks
</sa-field-label>
</sa-field>
<sa-field orientation="Horizontal">
<sa-input type="checkbox" id="finder-pref-external-disks"/>
<sa-field-label
for="finder-pref-external-disks"
class="font-normal">
External disks
</sa-field-label>
</sa-field>
<sa-field orientation="Horizontal">
<sa-input type="checkbox" id="finder-pref-cds-dvds"/>
<sa-field-label
for="finder-pref-cds-dvds"
class="font-normal">
CDs, DVDs, and iPods
</sa-field-label>
</sa-field>
<sa-field orientation="Horizontal">
<sa-input type="checkbox" id="finder-pref-connected-servers"/>
<sa-field-label
for="finder-pref-connected-servers"
class="font-normal">
Connected servers
</sa-field-label>
</sa-field>
</sa-field-group>
</sa-field-set>
<sa-field-separator/>
<sa-field orientation="Horizontal">
<sa-input type="checkbox" id="finder-pref-sync-folders" checked="checked"/>
<sa-field-content>
<sa-field-label for="finder-pref-sync-folders">
Sync Desktop & Documents folders
</sa-field-label>
<sa-field-description>
Your Desktop & Documents folders are being synced with iCloud Drive. You can access them from other
devices.
</sa-field-description>
</sa-field-content>
</sa-field>
</sa-field-group><sa-field-group>
<sa-field-set>
<sa-field-legend variant="Label">
Show these items on the desktop
</sa-field-legend>
<sa-field-description>
Select the items you want to show on the desktop.
</sa-field-description>
<sa-field-group class="gap-3">
<sa-input asp-for="Model.MustDisplayHardDisks"/>
<sa-input asp-for="Model.MustDisplayExternalDisks"/>
<sa-input asp-for="Model.MustDisplayCdDvd"/>
<sa-input asp-for="Model.MustDisplayConnectedServers"/>
</sa-field-group>
</sa-field-set>
<sa-field-separator/>
<sa-input asp-for="Model.MustSyncDesktopFolders"/>
</sa-field-group>public class CheckboxImplicitModel
{
[Display(Name = "CDs, DVDs, and iPods")]
public bool MustDisplayCdDvd { get; set; }
[Display(Name = "Connected servers")]
public bool MustDisplayConnectedServers { get; set; }
[Display(Name = "External disks")]
public bool MustDisplayExternalDisks { get; set; }
[Display(Name = "Hard disks")]
public bool MustDisplayHardDisks { get; set; }
[Display(
Name = "Sync Desktop & Documents folders",
Description = "Your Desktop & Documents folders are being synced with iCloud Drive. You can access them from other devices."
)]
public bool MustSyncDesktopFolders { get; set; }
}Radio
<sa-field-set>
<sa-field-legend variant="Label">Subscription Plan</sa-field-legend>
<sa-field-description>
Yearly and lifetime plans offer significant savings.
</sa-field-description>
<sa-field-group data-slot="radio-group">
<sa-field orientation="Horizontal">
<sa-input type="radio" value="monthly" id="plan-monthly" checked/>
<sa-field-label for="plan-monthly" class="font-normal">
Monthly ($9.99/month)
</sa-field-label>
</sa-field>
<sa-field orientation="Horizontal">
<sa-input type="radio" value="yearly" id="plan-yearly"/>
<sa-field-label for="plan-yearly" class="font-normal">
Yearly ($99.99/year)
</sa-field-label>
</sa-field>
<sa-field orientation="Horizontal">
<sa-input type="radio" value="lifetime" id="plan-lifetime"/>
<sa-field-label for="plan-lifetime" class="font-normal">
Lifetime ($299.99)
</sa-field-label>
</sa-field>
</sa-field-group>
</sa-field-set><sa-field-set>
<sa-field-legend variant="Label">Subscription Plan</sa-field-legend>
<sa-field-description>
Yearly and lifetime plans offer significant savings.
</sa-field-description>
<sa-field-group data-slot="radio-group">
<sa-input asp-for="Model.SubscriptionType" label="Monthly ($9.99/month)" type="radio" value="monthly"/>
<sa-input asp-for="Model.SubscriptionType" label="Yearly ($99.99/year)" type="radio" value="yearly"/>
<sa-input asp-for="Model.SubscriptionType" label="Lifetime ($299.99)" type="radio" value="lifetime"/>
</sa-field-group>
</sa-field-set>public class RadioImplicitModel
{
public string? SubscriptionType { get; set; }
}Fieldset
<sa-field-set>
<sa-field-legend>Address Information</sa-field-legend>
<sa-field-description>
We need your address to deliver your order.
</sa-field-description>
<sa-field-group>
<sa-field>
<sa-field-label for="street">Street Address</sa-field-label>
<sa-input id="street" type="text" placeholder="123 Main St"/>
</sa-field>
<div class="grid grid-cols-2 gap-4">
<sa-field>
<sa-field-label for="city">City</sa-field-label>
<sa-input id="city" type="text" placeholder="New York"/>
</sa-field>
<sa-field>
<sa-field-label for="postal-code">Postal Code</sa-field-label>
<sa-input id="postal-code" type="text" placeholder="90502"/>
</sa-field>
</div>
</sa-field-group>
</sa-field-set><sa-field-set>
<sa-field-legend>Address Information</sa-field-legend>
<sa-field-description>
We need your address to deliver your order.
</sa-field-description>
<sa-field-group>
<sa-input asp-for="Model.Street"/>
<div class="grid grid-cols-2 gap-4">
<sa-input asp-for="Model.City"/>
<sa-input asp-for="Model.PostalCode"/>
</div>
</sa-field-group>
</sa-field-set>public class FieldsetImplicitModel
{
[Display(Name = "Street Address", Prompt = "123 Main St")]
public string? Street { get; set; }
[Display(Name = "City", Prompt = "New York")]
public string? City { get; set; }
[Display(Name = "Postal Code", Prompt = "90502")]
public string? PostalCode { get; set; }
}Field Group
Stack <sa-field> components with <sa-field-group>. Add <sa-field-separator> to divide them. When grouping checkboxes or radio buttons, you can add data-slot="checkbox-group" or data-slot="radio-group" to tighten up spacing between the individual inputs.
<sa-field-group>
<sa-field-set>
<sa-field-label>Responses</sa-field-label>
<sa-field-description>
Get notified when ChatGPT responds to requests that take time, like
research or image generation.
</sa-field-description>
<sa-field-group data-slot="checkbox-group">
<sa-field orientation="Horizontal">
<sa-input type="checkbox" id="push" checked disabled/>
<sa-field-label for="push" class="font-normal">
Push notifications
</sa-field-label>
</sa-field>
</sa-field-group>
</sa-field-set>
<sa-field-separator/>
<sa-field-set>
<sa-field-label>Tasks</sa-field-label>
<sa-field-description>
Get notified when tasks you've created have updates. <a href="#">Manage tasks</a>
</sa-field-description>
<sa-field-group data-slot="checkbox-group">
<sa-field orientation="Horizontal">
<sa-input type="checkbox" id="push-tasks"/>
<sa-field-label for="push-tasks" class="font-normal">
Push notifications
</sa-field-label>
</sa-field>
<sa-field orientation="Horizontal">
<sa-input type="checkbox" id="email-tasks"/>
<sa-field-label for="email-tasks" class="font-normal">
Email notifications
</sa-field-label>
</sa-field>
</sa-field-group>
</sa-field-set>
</sa-field-group><sa-field-group>
<sa-field-set>
<sa-field-label>Responses</sa-field-label>
<sa-field-description>
Get notified when ChatGPT responds to requests that take time, like
research or image generation.
</sa-field-description>
<sa-field-group data-slot="checkbox-group">
<sa-input asp-for="Model.EnableResponsePushNotifications" disabled/>
</sa-field-group>
</sa-field-set>
<sa-field-separator/>
<sa-field-set>
<sa-field-label>Tasks</sa-field-label>
<sa-field-description>
Get notified when tasks you've created have updates. <a href="#">Manage tasks</a>
</sa-field-description>
<sa-field-group data-slot="checkbox-group">
<sa-input asp-for="Model.EnableTaskPushNotifications"/>
<sa-input asp-for="Model.EnableTaskEmailNotifications"/>
</sa-field-group>
</sa-field-set>
</sa-field-group>public class FieldGroupImplicitModel
{
[Display(Name = "Push notifications")]
public bool EnableResponsePushNotifications { get; set; }
[Display(Name = "Email notifications")]
public bool EnableTaskEmailNotifications { get; set; }
[Display(Name = "Push notifications")]
public bool EnableTaskPushNotifications { get; set; }
}