Visually speaking, on one of my MVC Views I have about 20 fields in standard vertical order, with the first 8 or so having optional [Create] boxes in same <div>
group over on the right.
My default tab order currently hits my first dropdown, then goes right to [Create], down to the next, then right, etc. What I would like to do set the TAB order to where it goes straight down my various fields and leave the [Create] boxes as optional for the user (or at the end of the tab order). While there seems to be a lot of discussion on this with a quick search, there seems to be inconsistent answers; a lot of them seemingly from a couple years ago regarding setting TAB Order in an EditorFor()
but being forced to use Custom Editor Templates or switch to TextBoxFor()
?
Hoping someone can weigh in on this. The below somewhat details my fields:
(8 of these DropDownListFor()):
@Html.DropDownListFor(model => model.STATUS_ID, (SelectList)ViewBag.Model_List, htmlAttributes: new { @class = "form-control dropdown", @id = "selectStatus" })
(12 of these EditorFor()):
@Html.EditorFor(model => model.NOTE, new { htmlAttributes = new { @class = "form-control" } })
To set the tab order, all you need to do is be able to add an extra attribute,
tabindex
to the generated field. That's easy enough with something likeTextBoxFor
orDropDownListFor
, since they actually take anhtmlAttributes
parameter specifically for this purpose:In the past, the same could not be said for
EditorFor
. Since it's a "templated" helper, the editor template, not the method call, effects what's generated. You can see this in the definition ofEditorFor
, as there's nohtmlAttributes
param like the other helpers have, but ratheradditionalViewData
.Starting with MVC 5.1, Microsoft made it possible to pass additional HTML attributes to
EditorFor
, via a specially namedViewData
key,"htmlAttributes"
. As a result, you can achieve the same thing as when using something likeTextBoxFor
, although it's a little more verbose:See, you're still actually passing
additionalViewData
here, but that additional view data contains an anonymous object keyed tohtmlAttributes
. The built-in editor templates, then, know how to utilizeViewData["htmlAttributes"]
to add additional attributes to the generated element. However, this only applies to the default editor templates because Microsoft has specifically programmed them to use this. As soon as you add your own custom editor templates, you're right back to where you started.There's a number of ways you could approach this with custom editor templates. First, you could just pass the tab index directly as view data, and utilize that in your template:
Then, in your editor template:
Second, you could mimic
EditorFor
's behavior with the default templates:Then, in your editor template:
However, that option doesn't allow you to have "default" attributes. It's an all or nothing approach. To truly be able to utilize
ViewData["htmlAttributes"]
as the built-in editor templates do, you'll need to combine the default attributes with the passed in ones, first, and then pass the whole shebang tohtmlAttributes
. I've got a blog post that discusses that in depth, but TL;DR: you'll need the following extension:And then you'll need to add the following to top of your custom editor templates:
You'd change the
defaultHtmlAttributesObject
variable depending on what attributes the generated input should have by default for that particular template.