Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

Web Tab Control

4.93/5 (12 votes)
22 May 2012CPOL6 min read 67.5K   2.5K  
A tab control for the web that can be created dynamically in C#. Uses JavaScript so tabs can be changed without refreshing the page allowing ease-of-use on things like Account Information pages.

Update: Ability to remember selected tab added! See C# code below!

Update: jQuery used - now allows jQuery animations to be set (from C# too) for the tab transitions.

Update: Use of HTML5 and CSS3 to bring decent borders and rounded corners - it looks better now basically :).

Introduction

I was recently developing a website that pulled lots of information from many sources and collated it into one account on the site. However, all that information had to be editable by the user whenever (s)he likes, through the site. Furthermore, a key aim of the site was ease of use and clarity of information. So, I had the dilemma of how to allow users to easily and clearly edit all their information without having one long page with lots of editable fields. The obvious solution was to use a tab control, but predictably nothing useable existed on the web already. So I created my own custom web control that I present in this article which I hope others will find easy to setup and use and as useful as I have.

Background

It would probably be useful if you, know basic CSS, HTML, JavaScript and at least have an idea of how to create dynamic content in C#. I would suggest the following links to be good starting points:

Using the Code

Screen Shots

Image 1

Initial View of the Tab Control - Basic Tab

Image 2

Personal Tab of the Tab Control

Image 3

After clicking the test button, the text box on the Basic tab is set to 'Test OK. :)'

To show how the code works, we will step through the server side code that builds the Default.aspx page. The code looks as follows:

C#
//Create a tab control
TabControl TheTabCtrl = new TabControl("InfoTabCtrl");

//Block: Create and add a new tab page - BasicPage
TabPage BasicPage = new TabPage("BasicInfoTabPage", "Basic");

BasicPage.Controls.Add(ABox);

TheTabCtrl.Tabs.Add(BasicPage);
//End Block

//Block: Create and add a new tab page - PersonalPage
TabPage PersonalPage = new TabPage("PersonalInfoTabPage", "Personal");

Button AButton = new Button();
AButton.Text = "Test";
AButton.Click += new EventHandler(AButton_Click);
PersonalPage.Controls.Add(AButton);

TheTabCtrl.Tabs.Add(PersonalPage);
//End Block

//Add the tab control to the page output.
form1.Controls.Add(TheTabCtrl.GetControl);

The first line of code creates a new tab control called TheTabCtrl. The constructor takes one argument, Id. This should be a unique Id of the tab control as it is used in the JavaScript (later in this article) to keep track of what tab is selected. TheTabCtrl can then be used to add tab pages and generate the tab control output.

Next, the code creates a new TabPage. The constructor for a tab page takes two arguments, the first is a unique Id of the tab page, this is used in the JavaScript (later in this article) to change the currently displayed tab. The second argument is the Name of the tab. This is what the tab title will be when it is shown the user. In this case, I have picked 'Basic' as the title as that was one of the categories of information my website needed.

To add controls to the tab is very simple, as shown in the next line. All that is required is to call ATabPage.Controls.Add. You can add any object that derives from the System.Web.UI.Control class; this includes all the WebControls and HtmlControls. The Controls collection is simply a list of Control objects that get added to the tab later.
The next block of code just adds another tab page, called Personal, with a button on it to allow me to demonstrate how the tab control works with multiple tabs.

The last line of code adds the tab control to the page. I decided not to derive the TabControl class from the System.Web.UI.Control class as it would have meant overriding many more methods than I needed to. Instead, I have created a property, GetControl that returns a WebControl that can be added to any part of a page. (Note, If using controls with events in any of your tab pages, the TabControl must be added in the Page_Load method so that the control's events link up.) The GetCotnrol property code looks like the following:

C#
public WebControl GetControl
{
    get
    {
        WebControl TabCtrlWrapper = new WebControl(HtmlTextWriterTag.Div);
        TabCtrlWrapper.CssClass = ClassName;
        TabCtrlWrapper.ID = Id;

        TabCtrlWrapper.Controls.Add(TabSelectionControl);

        foreach (TabPage APage in Tabs)
        {
            TabCtrlWrapper.Controls.Add(APage.GetControl);
        }

        Literal BreakLit = new Literal();
        BreakLit.Text = "<div style=\"width:100%; float:none; 
        line-height:0px;\"> <script type=\"text/javascript\">" + 
        CreateChangeTabCall(Tabs[SelectedTab].Id) + "</script></div>";
        TabCtrlWrapper.Controls.Add(BreakLit);

        return TabCtrlWrapper;
    }
}

The code first creates a WebControl, the final control that will be returned, and sets its Id and CssClass. Id was given in the constructor, the CssClass is by default set to ClassName which is, by default, set to 'TabControl'. This links to the CSS file provided allowing easy styling of the tab control. The code then adds the TabSelectionControl (see later for more detail). This control is what allows the user to select different tabs. Then, all the tab pages are enumerated and their controls (see later) added to the final control. Initially, these pages have display:none; to hide them all from the user. The block of code after the loop adds a div, with a space to force the height of the TabControl to be full height including tab pages and TabSelectionControl. A quirk of CSS and floats is that a parent element without text in it, but with floating child elements, will only be the height of those elements if there is some text in a non-floating child element - complicated and weird I know, but the solution above is quite simple. line-height is set to 0 to hide the contents of the div and make it seem as if it weren't there. The JavaScript code runs when the tab control has loaded and so sets the initially selected tab. This can be changed server side by setting the SelectedTab property, which is simply an index of the tab in the list of tabs that the control has.

The Tab Selection Control

Creates the web control that forms the tab selection section. This code enumerates all the tabs, adding a separate 'button area' for each one that displays the name of the tab. Each 'button area' has an onclick event that runs the JavaScript code that changes the tab.

C#
WebControl TheCtrl = new WebControl(HtmlTextWriterTag.Div);
TheCtrl.CssClass = "TabPageSelectionControl";

//Enumerate all tabs, adding a 'button area' for each one.
foreach (TabPage ATab in Tabs)
{
    //Create the web control that will be the 'button area'
    WebControl TabCtrl = new WebControl(HtmlTextWriterTag.Div);
    TabCtrl.CssClass = "TabPageSelectionTitle";
    //Add the onclick attribute using the (custom) 
    //CreateChangeTabCall method with the relevant TabId.
    TabCtrl.Attributes.Add("onclick", CreateChangeTabCall(ATab.Id));
    TabCtrl.Attributes.Add("style", "background-color:;");
    TabCtrl.ID = ATab.Id + "TitleCtrl";

    //Add a literal to display the name of the tab.
    Literal NameLit = new Literal();
    NameLit.Text = ATab.Name;
    TabCtrl.Controls.Add(NameLit);

    //Add the button area to the selection control.
    TheCtrl.Controls.Add(TabCtrl);
}

return TheCtrl;

The TabPage Control

Adds the title of the tab to the tab page control, then adds all the controls specified by the user in the Controls collection.

C#
WebControl TabPageWrapper = new WebControl(HtmlTextWriterTag.Div);
TabPageWrapper.CssClass = ClassName;
TabPageWrapper.ID = Id;
TabPageWrapper.Attributes.Add("style", "display:none;");

TabPageWrapper.Controls.Add(TitleCtrl);
foreach (Control ACtrl in Controls)
{
    TabPageWrapper.Controls.Add(ACtrl);
}

return TabPageWrapper;

Code to re-select the user's last tab:

C#
if (IsPostBack)
{
    //Gets the selected tab's Id from the posted form
    string value = Request.Form[TheTabCtrl.Id + "_SelectedTab"];
    //Checks to make sure it's not an empty/null Id i.e. there actually wasn't one selected.
    if(!string.IsNullOrEmpty(value))
    {
        try
        {
            //Tries to selected the tab with that Id.
            //Try-catch used in case that tab no longer exists.
            TheTabCtrl.SelectedTab = TheTabCtrl.Tabs.IndexOf(TheTabCtrl.Tabs.Where(x => x.Id == value).First()); 
        }
        catch
        {
        }
    }
}  

Using new bits of the JavaScript you can now get the last selected tab for your tab controls from the form post back. See above code for a how-to :)

Client Side Script

So I've shown how all the server side stuff works, but how does the client side work. Well, I'll start with the JavaScript, then I'll explain how to change the styling. The JavaScript code is very simple and looks like this:

JavaScript
var CurrentTabs = [];

//The colour of the tab selector when selected
var SelectedBgColour = "#C7E9FF";
//The colour of the tab selector when not selected
var NotSelectedBgColour = "#99C8E8";

//Changes a tab control to a different tab using wanted jQuery effects
//TabControlName - The name of the tab control you are changing
//Id - The (full) Id of the tab to change to
//EffectIn (Opt) - The effect to use for bringing in the new tab. Default : fade
//EffectOut (Opt) - The effect to use for taking out the current tab. Default : fade
//Speed (Opt) - How long the transition should take (in milliseconds) : Default : 300
function ChangeTab(TabControlName, Id, EffectIn, EffectOut, Speed)
{
    //If not already showing the current tab
    if (CurrentTabs[TabControlName] != Id)
    {
        //Set-up the default values if necessary
        //JS allows testing for null/undefined by just evaluating the object as a boolean
        if (!EffectIn)
            EffectIn = "fade";
        if (!EffectOut)
            EffectOut = "fade";
        if (!Speed)
            Speed = 300;
        
        if (CurrentTabs[TabControlName] != null)
        {
            $("#" + CurrentTabs[TabControlName])
                    .hide(EffectOut, { direction: "vertical" }, Speed, null);
            $("#" + CurrentTabs[TabControlName] + "TitleCtrl")
                    .animate({ backgroundColor: NotSelectedBgColour }, Speed);
        } 
        
        //Resizes the tabs wrapper to fit the new tab
        $("#" + Id)
            .parent()
            .css("height", $("#" + Id)
            //Shows the current tab then gets its outer height including margins
            .show(EffectIn, {}, Speed, null)
            .outerHeight(true));
        //Changes the new tab's title control bgColour to selected
        $("#" + Id + "TitleCtrl").animate({ backgroundColor: SelectedBgColour }, Speed);

        //Stores the new tab as being the current tab (for page submission)
        CurrentTabs[TabControlName] = Id;

        //Stores the new tab in the form data for postback
        $("#" + TabControlName + "_SelectedTab").val(Id);
    }
}
$(document).ready(function ()
{
    //Set all the title control backgrounds to the not selected colour
    //Saves having to write it in two places i.e. the CSS and the JavaScript
    $(".TabPageSelectionTitle").css("background-color", NotSelectedBgColour);
}); 

CurrentTabs keeps track of what tab is selected on which tab control. An array is used so that multiple tab control can be on the same page without conflict.

SelectedBgColour is the colour code or name of the background colour the tab title (in the tab selection control) of a selected tab, should have when it is selected.

The ChangeTab method takes the currently selected tab (if there is one), hides it, then displays the desired selected tab. It also changes the relevant styles (see above) and then stores the new selected tab. The code is self explanatory.

Styling

All the styling, except the selected tab's title background colour, is done in one short CSS file. As shown below (and explained in comments in the CSS), it is very easy to change the look of the TabControl. I have chosen stark, garish colours that contrast horribly simply to show clearly what the sections of the tab control are, you will definitely want to change these. So, the CSS:

CSS
.TabControlTabsWrapper
{
    position:relative;
    width:100%;
    height:100%;
    overflow:hidden;
    /*Set this to change the tab background colour - this is a very light blue - off-white
          almost*/
    background-color:#FAFDFF;
    
    border:solid #000000;
    border-width:medium;
    border-bottom-left-radius:10px;
    border-bottom-right-radius:10px;
    -moz-border-bottom-left-radius:10px; /* Firefox 3.6 and earlier */
    -moz-border-bottom-right-radius:10px; /* Firefox 3.6 and earlier */
} 
.TabPageSelectionTitle
{
    float:left;
    padding:2px;
    padding-left:4px;
    padding-right:4px;
    border-right:2px solid #000000;
            
    border:solid #000000;
    border-width:medium;
    border-bottom:0px;
    border-top-left-radius:10px;
    border-top-right-radius:10px;
    -moz-border-top-left-radius:10px; /* Firefox 3.6 and earlier */
    -moz-border-top-right-radius:10px; /* Firefox 3.6 and earlier */
} 

Not all the CSS but the bits that are useful - these set up the borders and corners of the borders. I deliberately left a square corner on the top-right of the tabs, I think it looks nice both in contrast and it mirrors the other side too.

History

  • 7/5/2011 - Initial post
  • 22/5/2012 - jQuery and HTML5/CSS3 update

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)