As you may know, ASP.NET controls often render with client-side IDs different than what’s declared in your aspx code. Especially when they’re nested in other controls (Tabs, Wizard, GridView, etc). When working with them on the server side this isn’t an issue, but tends to throw a monkey wrench into the gears of client-side development. Here’s an example:

<asp:Wizard runat="server" ID="Wizard1">
  <WizardSteps>
    <asp:WizardStep>
      <asp:TextBox runat="server" id="TextBox1" />
    </asp:WizardStep>
    <asp:WizardStep>
      <asp:Button runat="server" ID="Button1" />
    </asp:WizardStep>
  </WizardSteps>
</asp:Wizard>

TextBox1 and Button1 are accessible in code-behind via their declarative IDs, as we’d expect. However, trying to use $get() or getElementById() on TextBox1 or Button1 will fail. As it turns out, TextBox1 is rendered as Wizard1_TextBox1 and Button1 is rendered as Wizard1_Button1.

A FireBug screenshot of the modified ClientID

One solution is to hard code those rendered values in your JavaScript. $get(‘Wizard1_TextBox1′) will correctly reference TextBox1 on the client side, but doing it that way is a maintenance nightmare. What would have otherwise been innocuous changes to the structure of your page could now break your client script. Not good.

There must be a better way!

Indeed there is. The better solution is to use inline ASP.NET code to inject the control’s ClientID property:

$get('<%= TextBox1.ClientID %>')

Now the correct client element ID is referenced, regardless of the structure of the page and the nesting level of the control.

In my opinion, the very slight performance cost of this method is well worth it to make your client scripting more resilient to change.