Advanced Customization of the jQuery Mobile Buttons

There are many ways to skin a cat

By default, jQuery Mobile offers a series of themes that you can use in your project. Chances are that your project has been designed with unique buttons and elements that defer from the standard  jQuery Mobile Themes. In this article I will show a couple of techniques that you can use to do advanced customization of a jQuery Mobile Button in a way  that your code can be reused across multiple projects. Here is the list of points that I will touch upon:

  1. The structure of  the jQuery Mobile Button
  2. Simple customization
  3. Adding a custom theme
  4. Reset the button theme
  5. Advanced element targeting
  6. Adding elements using CSS
  7. Adding elements using Javascript
  8. Icon-only buttons
  9. Targeting buttons by context
  10. Conclusion

The structure of  the jQuery Mobile Button

The first thing that we need to keep in mind is, what are the HTML elements that we are going to modify. In the case of a jQuery Mobile Button, the HTML code that you define is different from the HTML code that is rendered when the page is done loading:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!-- original button (before loading) -->
<a href="#another-page"
   data-role="button"
   data-theme="a"
   data-icon="star">I am a button
</a>
 
<!-- modified button (after loading) -->
<a href="#another-page"
    data-role="button"
    data-icon="star"
    class="ui-btn-right ui-btn ui-shadow ui-btn-corner-all ui-btn-icon-left ui-btn-up-a"
    data-corners="true"
    data-shadow="true"
    data-iconshadow="true"
    data-wrapperels="span"
    data-theme="a">
    <span class="ui-btn-inner ui-btn-corner-all">
        <span class="ui-btn-text">I am a button</span>
        <span class="ui-icon ui-icon-star ui-icon-shadow">&nbsp;</span>
    </span>
</a>
<!-- original button (before loading) -->
<a href="#another-page"
   data-role="button"
   data-theme="a"
   data-icon="star">I am a button
</a>

<!-- modified button (after loading) -->
<a href="#another-page"
	data-role="button"
	data-icon="star"
	class="ui-btn-right ui-btn ui-shadow ui-btn-corner-all ui-btn-icon-left ui-btn-up-a"
	data-corners="true"
	data-shadow="true"
	data-iconshadow="true"
	data-wrapperels="span"
	data-theme="a">
	<span class="ui-btn-inner ui-btn-corner-all">
		<span class="ui-btn-text">I am a button</span>
		<span class="ui-icon ui-icon-star ui-icon-shadow">&nbsp;</span>
	</span>
</a>

 

The modified HTML structure takes multiple CSS rules in order to render the final button. When you look at the name of some of the CSS classes you may inquire which part of the button is rendered on each element. For instance, the positioning of the button is delegated to the “a” tag. The class ui-btn-left will force the button to float to the left side if the button is located inside the page header (this class is only assigned to the first instance of a button).

The different visual states of the buttons can be access from the “a” tag. In this example the button uses the theme a. jQuery Mobile automatically add the CSS class ui-btn-up-a which will allow us to customize the  look-and-feel of the button in its default state (when the mouse is positioned outside of the button). When the mouse hovers the button, or when we click on it, this class is replaced with ui-btn-hover-a and ui-btn-down-a respectively. Similarly, when we choose a different theme, the letter “a” in the name of the classes is replaced with the name of the theme (i.e. ui-btn-up-custom).

The body of the button is represented by the span.ui-btn-inner. This element is responsible for the background color of the button. You can modify the way the label of the button by targeting the span.ui-btn-text element. As you can predict, the icon of the button is rendered inside the span.ui-icon.

The final look-and-feel is the result of a combination of the background colors, borders, and shadows. This is a complex setup, but the jQuery Mobile Framework provides easy ways to create variations of the button.

 

Simple customization

Although this article is about advanced customization, I will touch on some of the basic techniques.

The Themeroller

You are probably familiar with the jQuery Mobile Themeroller. This is an online tool that allows you to customize global and theme-specific parameter to control the fonts, color, borders and shadows of the standard jQuery Mobile elements.

jQuery Mobile Themeroller

 

If you have not seen the Themeroller tool, you should visit the jQuery Mobile site and learn about it. It is a fun tool to play with. After you are done creating you theme you can download a archive file (.zip) containing the file that you will need to reference in you project (Visit jQuery Mobile Themeroller).

 

Using Custom Icons

In some cases you may want to simply change the icon of a button. The way to do that is by adding or replacing the icon attribute in your button HTML code. Inside the button, the span tag that controls the icon will inherit a CSS class that will contain the name of your icon. This will allow you to right the appropriate CSS code to add a new icon. One thing to keep in mind is that the default size of the icon is 18px x 18px. It is also placed inside a circular shape with a shadow effects applied to it. The following code show how to add a logo icon (24×24 pixles) and remove the shadow effect:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!-- HTML code -->
<a href="#another-page"
    data-role="button"
    data-iconshadow="false"
    data-corners="false"
    data-theme="logo"
    data-icon="logo">Appcropolis
</a>
 
<!-- CSS code -->
<style type="text/css">
.ui-icon-logo {
    background-image: url('logo.png');
    background-color: rgba(0, 0, 0, 0);
    width:24px;
    height: 24px;
    margin-top: -11px !important; /* adjust vertical position (top value is set to 50%) */
    }
</style>
<!-- HTML code -->
<a href="#another-page"
    data-role="button"
    data-iconshadow="false"
    data-corners="false"
    data-theme="logo"
    data-icon="logo">Appcropolis
</a>

<!-- CSS code -->
<style type="text/css">
.ui-icon-logo {
	background-image: url('logo.png');
	background-color: rgba(0, 0, 0, 0);
	width:24px;
	height: 24px;
	margin-top: -11px !important; /* adjust vertical position (top value is set to 50%) */
	}
</style>

Creating custom icon for a jQuery Mobile Button

 

Controlling the position of the icon

This is probably on of the easiest thing that you can change. By  simple adding the attribute data-iconpos=”right” you can float the icon to the right. This attribute accept the following values: left, right, top, button, and notext which remove the button label, leaving just the icon.

 

Selection a default theme

You can have more control over the different parts and states of the button when you add a custom theme. The jQuery Mobile Framework provides 5 default swatches. They are identified with the letters “a” thru “e“. You may choose other letters to create your own theme or simply assign a name to you theme.

jQuery Mobile Default Swatches

jQuery Mobile default swatches

 

Adding a custom theme

When you assign a custom theme to a button, jQuery Mobile assigns several CSS classes to different part of the button that you can use to add your custom code. Here is an example of a theme that I will ios:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<!-- HTML code -->
<a href="#another-page"
    data-role="button"
    data-theme="ios">Appcropolis
</a>
 
<!-- CSS code -->
<style type="text/css">
/* up state */
.ui-btn-up-ios,
.ui-btn-hover-ios,
.ui-btn-down-ios {
    border-radius: 0px; -webkit-border-radius: 0px; -moz-border-radius: 0px;
    box-shadow: none !important; -webkit-box-shadow: none !important; -moz-box-shadow: none !important;
    text-decoration: none;
    }
    .ui-btn-up-ios .ui-btn-inner,
    .ui-btn-hover-ios .ui-btn-inner,
    .ui-btn-down-ios .ui-btn-inner {
        color: white;
        overflow: visible;
        text-shadow: 0 -1px 0 #000;
        padding-left: 10px !important;
        padding-right: 10px !important;
        border: 1px solid #333;
        border-radius: 5px; -webkit-border-radius: 5px; -moz-border-radius: 5px;
        background: -webkit-linear-gradient(top, #89A0BE 0%,#5877A2 50%,#486A9A 51%,#4A6C9B 100%);
        box-shadow: 0 1px 0 rgba(255,255,255, 0.25), inset 0 1px 1px rgba(0,0,0, 0.2);
            -webkit-box-shadow: 0 1px 0 rgba(255,255,255, 0.25), inset 0 1px 1px rgba(0,0,0, 0.2);
            -moz-box-shadow: 0 1px 0 rgba(255,255,255, 0.25), inset 0 1px 1px rgba(0,0,0, 0.2);
        }
 
    /* hover state color */
    .ui-btn-hover-ios .ui-btn-inner {
        background: -webkit-linear-gradient(top, #89A0BE 0%,#5877A2 50%,#486A9A 51%,#4A6C9B 100%); /* add a different gradient here */
        }
 
    /* down state color */
    .ui-btn-down-ios .ui-btn-inner {
        background: -webkit-linear-gradient(top, #89A0BE 0%,#5877A2 50%,#486A9A 51%,#4A6C9B 100%); /* add a different gradient here */
        }
</style>
<!-- HTML code -->
<a href="#another-page"
    data-role="button"
    data-theme="ios">Appcropolis
</a>

<!-- CSS code -->
<style type="text/css">
/* up state */
.ui-btn-up-ios,
.ui-btn-hover-ios,
.ui-btn-down-ios {
    border-radius: 0px; -webkit-border-radius: 0px; -moz-border-radius: 0px;
    box-shadow: none !important; -webkit-box-shadow: none !important; -moz-box-shadow: none !important;
    text-decoration: none;
	}
	.ui-btn-up-ios .ui-btn-inner,
	.ui-btn-hover-ios .ui-btn-inner,
	.ui-btn-down-ios .ui-btn-inner {
        color: white;
        overflow: visible;
    	text-shadow: 0 -1px 0 #000;
        padding-left: 10px !important;
        padding-right: 10px !important;
        border: 1px solid #333;
        border-radius: 5px; -webkit-border-radius: 5px; -moz-border-radius: 5px;
        background: -webkit-linear-gradient(top, #89A0BE 0%,#5877A2 50%,#486A9A 51%,#4A6C9B 100%);
        box-shadow: 0 1px 0 rgba(255,255,255, 0.25), inset 0 1px 1px rgba(0,0,0, 0.2);
        	-webkit-box-shadow: 0 1px 0 rgba(255,255,255, 0.25), inset 0 1px 1px rgba(0,0,0, 0.2);
        	-moz-box-shadow: 0 1px 0 rgba(255,255,255, 0.25), inset 0 1px 1px rgba(0,0,0, 0.2);
		}

	/* hover state color */
	.ui-btn-hover-ios .ui-btn-inner {
        background: -webkit-linear-gradient(top, #89A0BE 0%,#5877A2 50%,#486A9A 51%,#4A6C9B 100%); /* add a different gradient here */
		}

	/* down state color */
	.ui-btn-down-ios .ui-btn-inner {
        background: -webkit-linear-gradient(top, #89A0BE 0%,#5877A2 50%,#486A9A 51%,#4A6C9B 100%); /* add a different gradient here */
		}
</style>

jQuery Mobile Button - iOS Theme

 

As you can see the CSS rules have to be defined for the three different states of the button. In this example I chose to remove the shadow and change the button radius using some CSS rules.

 

Reset the button theme

So far, the examples that I provided do not require much code. As you create more themes, for more elements, for more project, you will see the amount of code growing exponentially. You might end up copying-and-pasting code from one project to another or even between pages.

To make sure that you reuse code from one theme to another, it makes sense to keep the CSS reset rules in a common file. In this way you will only write theme-specific rules on a theme by theme basis. Writing the reset rules separate will give you a blank canvas that you can customize with less effort. Here is a suggested reset code:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<!-- normal button -->
<a href="#page2"
   data-role="button">Default button
</a>  
 
<!-- reset only -->
<a href="#another-page"
    data-role="button"
    data-theme="reset">Reset button
</a>
 
<!-- no-background -->
<a href="#another-page"
    data-role="button"
    data-theme="reset"
    class="app-theme-none">No-background
</a>
 
<!-- CSS reset rules -->
<style type="text/css">
/* reset buttons */
a[data-role="button"][data-theme="reset"] {
    border-radius: 0px; -webkit-border-radius: 0px; -moz-border-radius: 0px;
    box-shadow: none !important; -webkit-box-shadow: none !important; -moz-box-shadow: none !important;
    text-decoration: none;
    }
    a[data-role="button"][data-theme="reset"] .ui-btn-inner {
        color: white;
        overflow: visible;
        text-shadow: 0 -1px 0 #000;
        padding-left: 10px !important;
        padding-right: 10px !important;
        border: 1px solid #333;
        border-radius: 5px; -webkit-border-radius: 5px; -moz-border-radius: 5px;
        background: #333;
        box-shadow: 0 1px 0 rgba(255,255,255, 0.25), inset 0 1px 1px rgba(0,0,0, 0.2);
            -webkit-box-shadow: 0 1px 0 rgba(255,255,255, 0.25), inset 0 1px 1px rgba(0,0,0, 0.2);
            -moz-box-shadow: 0 1px 0 rgba(255,255,255, 0.25), inset 0 1px 1px rgba(0,0,0, 0.2);
        }
 
    /* no-background */
    a[data-role="button"][data-theme="reset"].app-theme-none .ui-btn-inner {
        color: #222;
        background: none;
        border: none;
        box-shadow: none;
        text-shadow: none;
        }
</style>
<!-- normal button -->
<a href="#page2"
   data-role="button">Default button
</a>  

<!-- reset only -->
<a href="#another-page"
    data-role="button"
    data-theme="reset">Reset button
</a>

<!-- no-background -->
<a href="#another-page"
    data-role="button"
    data-theme="reset"
    class="app-theme-none">No-background
</a>

<!-- CSS reset rules -->
<style type="text/css">
/* reset buttons */
a[data-role="button"][data-theme="reset"] {
    border-radius: 0px; -webkit-border-radius: 0px; -moz-border-radius: 0px;
    box-shadow: none !important; -webkit-box-shadow: none !important; -moz-box-shadow: none !important;
    text-decoration: none;
	}
	a[data-role="button"][data-theme="reset"] .ui-btn-inner {
        color: white;
        overflow: visible;
    	text-shadow: 0 -1px 0 #000;
        padding-left: 10px !important;
        padding-right: 10px !important;
        border: 1px solid #333;
        border-radius: 5px; -webkit-border-radius: 5px; -moz-border-radius: 5px;
        background: #333;
        box-shadow: 0 1px 0 rgba(255,255,255, 0.25), inset 0 1px 1px rgba(0,0,0, 0.2);
        	-webkit-box-shadow: 0 1px 0 rgba(255,255,255, 0.25), inset 0 1px 1px rgba(0,0,0, 0.2);
        	-moz-box-shadow: 0 1px 0 rgba(255,255,255, 0.25), inset 0 1px 1px rgba(0,0,0, 0.2);
		}

	/* no-background */
	a[data-role="button"][data-theme="reset"].app-theme-none .ui-btn-inner {
	    color: #222;
	    background: none;
	    border: none;
	    box-shadow: none;
	   	text-shadow: none;
		}
</style>

jQuery Mobile Reset Buttons

 

Notice that in this example I am only targeting elements that are buttons and have the reset theme assigned. The CSS reset rules that are valid for a button element might not be valid for a navigation element. Instead of writing rules around the the reset class (ui-btn-up-reset, ui-btn-hover-reset, and ui-btn-down-reset) it makes sense to target the theme and the specific element type. On top of the reset theme we can add other CSS classes to modify the appearance of the button without having to repeat the reset rules.

The idea behind this type of manipulation is not to complicate things. It is to assure that we can preserve the HTML structure of the pages and create any type of button around the HTML elements that are generated by the jQuery Mobile Framework.

 

 

Advanced element targeting

Now that we have an idea about the some of the options that we have to customize a button, let’s combine what we discuss so far. The following example will show how to create a theme family that you can extend while preserving the reset rules in a separate file:

The complete HTML code (app-ios-theme.html)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
        <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script>
        <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" />
        <link rel="stylesheet" href="resources/css/app-reset.css" />
        <link rel="stylesheet" href="resources/css/app-theme-ios.css" />
        <title>Appcropolis Theme iOS</title>
    </head>
    <body>
        <div data-role="page" id="ios-theme">
            <div data-theme="a" data-role="header">
                <h3>Appcropolis Theme iOS</h3>
            </div><!-- /header -->
            <div data-role="content">
                <!-- iOS Default -->
                <a href="#another-page"
                    data-role="button"
                    data-theme="reset"
                    class="ios">iOS Default
                </a>
 
                <!-- iOS Red -->
                <a href="#another-page"
                    data-role="button"
                    data-theme="reset"
                    class="ios red">iOS Red
                </a>
 
                <!-- iOS Black -->
                <a href="#another-page"
                    data-role="button"
                    data-theme="reset"
                    class="ios black">iOS Black
                </a>
                <!-- iOS Blue -->
                <a href="#another-page"
                    data-role="button"
                    data-theme="reset"
                    class="ios blue">iOS Blue
                </a>
            </div><!-- /content -->
        </div><!-- /page -->
    </body>
</html>
<!DOCTYPE html>
<html>
	<head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
        <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script>
        <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" />
        <link rel="stylesheet" href="resources/css/app-reset.css" />
        <link rel="stylesheet" href="resources/css/app-theme-ios.css" />
		<title>Appcropolis Theme iOS</title>
	</head>
	<body>
        <div data-role="page" id="ios-theme">
            <div data-theme="a" data-role="header">
                <h3>Appcropolis Theme iOS</h3>
            </div><!-- /header -->
            <div data-role="content">
				<!-- iOS Default -->
				<a href="#another-page"
				    data-role="button"
				    data-theme="reset"
				    class="ios">iOS Default
				</a>

				<!-- iOS Red -->
				<a href="#another-page"
				    data-role="button"
				    data-theme="reset"
				    class="ios red">iOS Red
				</a>

				<!-- iOS Black -->
				<a href="#another-page"
				    data-role="button"
				    data-theme="reset"
				    class="ios black">iOS Black
				</a>
				<!-- iOS Blue -->
				<a href="#another-page"
				    data-role="button"
				    data-theme="reset"
				    class="ios blue">iOS Blue
				</a>
            </div><!-- /content -->
        </div><!-- /page -->
	</body>
</html>

 

The reset code (app-reset.css)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
/* reset buttons */
a[data-role="button"][data-theme="reset"] {
    border-radius: 0px; -webkit-border-radius: 0px; -moz-border-radius: 0px;
    box-shadow: none !important; -webkit-box-shadow: none !important; -moz-box-shadow: none !important;
    text-decoration: none;
    }
    a[data-role="button"][data-theme="reset"] .ui-btn-inner {
        color: white;
        overflow: visible;
        text-shadow: 0 -1px 0 #000;
        padding-left: 10px !important;
        padding-right: 10px !important;
        border: 1px solid #333;
        border-radius: 5px; -webkit-border-radius: 5px; -moz-border-radius: 5px;
        background: #333;
        box-shadow: 0 1px 0 rgba(255,255,255, 0.25), inset 0 1px 1px rgba(0,0,0, 0.2);
            -webkit-box-shadow: 0 1px 0 rgba(255,255,255, 0.25), inset 0 1px 1px rgba(0,0,0, 0.2);
            -moz-box-shadow: 0 1px 0 rgba(255,255,255, 0.25), inset 0 1px 1px rgba(0,0,0, 0.2);
        }
 
    /* remove button background */
    a[data-role="button"][data-theme="reset"].app-theme-none .ui-btn-inner {
        color: #222;
        background: none !important;
        border: none !important;
        box-shadow: none !important;
        text-shadow: none !important;
        }
 
        /* remove icon background */
        a[data-role="button"][data-theme="reset"].app-theme-none .ui-btn-inner .ui-icon {
            background-color: rgba(0, 0, 0, 0);
            border: none;
            box-shadow: none;
            }
 
    /* hide button text
     * NOTE: data-iconpos="notext" does not affect the navbar. It's overriden by data-iconpos="top"
     */
    a[data-theme="reset"][data-role="button"].notext .ui-btn-text {
        display: none;
        }
 
/* when buttons are inside a controlgroup */
.ui-controlgroup a[data-role="button"][data-theme="reset"] {
    border-right: none;
    margin-left: 2px;
    }
.ui-controlgroup a[data-role="button"][data-theme="reset"] .ui-btn-inner {
    }
    /* adjust inner radius and left padding */
    .ui-controlgroup a[data-role="button"][data-theme="reset"] .ui-btn-inner {
        border-radius: 0px; -webkit-border-radius: 0px; -moz-border-radius: 0px;
        padding-left: 35px !important;
        border-right: none !important;
        }
    .ui-controlgroup a[data-role="button"][data-theme="reset"]:first-child .ui-btn-inner {
        border-radius: 5px 0px 0px 5px; -webkit-border-radius: 5px 0px 0px 5px; -moz-border-radius: 5px 0px 0px 5px;
        }
    .ui-controlgroup a[data-role="button"][data-theme="reset"]:last-child .ui-btn-inner {
        border-radius: 0px 5px 5px 0px; -webkit-border-radius: 0px 5px 5px 0px; -moz-border-radius: 0px 5px 5px 0px;
        border-right: 1px solid #333 !important;
        }
/* reset buttons */
a[data-role="button"][data-theme="reset"] {
    border-radius: 0px; -webkit-border-radius: 0px; -moz-border-radius: 0px;
    box-shadow: none !important; -webkit-box-shadow: none !important; -moz-box-shadow: none !important;
    text-decoration: none;
	}
	a[data-role="button"][data-theme="reset"] .ui-btn-inner {
        color: white;
        overflow: visible;
    	text-shadow: 0 -1px 0 #000;
        padding-left: 10px !important;
        padding-right: 10px !important;
        border: 1px solid #333;
        border-radius: 5px; -webkit-border-radius: 5px; -moz-border-radius: 5px;
        background: #333;
        box-shadow: 0 1px 0 rgba(255,255,255, 0.25), inset 0 1px 1px rgba(0,0,0, 0.2);
        	-webkit-box-shadow: 0 1px 0 rgba(255,255,255, 0.25), inset 0 1px 1px rgba(0,0,0, 0.2);
        	-moz-box-shadow: 0 1px 0 rgba(255,255,255, 0.25), inset 0 1px 1px rgba(0,0,0, 0.2);
		}

	/* remove button background */
	a[data-role="button"][data-theme="reset"].app-theme-none .ui-btn-inner {
	    color: #222;
	    background: none !important;
	    border: none !important;
	    box-shadow: none !important;
	   	text-shadow: none !important;
		}

		/* remove icon background */
		a[data-role="button"][data-theme="reset"].app-theme-none .ui-btn-inner .ui-icon {
		    background-color: rgba(0, 0, 0, 0);
		    border: none;
		    box-shadow: none;
			}

	/* hide button text
	 * NOTE: data-iconpos="notext" does not affect the navbar. It's overriden by data-iconpos="top"
	 */
	a[data-theme="reset"][data-role="button"].notext .ui-btn-text {
		display: none;
		}

/* when buttons are inside a controlgroup */
.ui-controlgroup a[data-role="button"][data-theme="reset"] {
	border-right: none;
	margin-left: 2px;
	}
.ui-controlgroup a[data-role="button"][data-theme="reset"] .ui-btn-inner {
	}
	/* adjust inner radius and left padding */
	.ui-controlgroup a[data-role="button"][data-theme="reset"] .ui-btn-inner {
	    border-radius: 0px; -webkit-border-radius: 0px; -moz-border-radius: 0px;
	    padding-left: 35px !important;
		border-right: none !important;
		}
	.ui-controlgroup a[data-role="button"][data-theme="reset"]:first-child .ui-btn-inner {
		border-radius: 5px 0px 0px 5px; -webkit-border-radius: 5px 0px 0px 5px; -moz-border-radius: 5px 0px 0px 5px;
		}
	.ui-controlgroup a[data-role="button"][data-theme="reset"]:last-child .ui-btn-inner {
		border-radius: 0px 5px 5px 0px; -webkit-border-radius: 0px 5px 5px 0px; -moz-border-radius: 0px 5px 5px 0px;
       	border-right: 1px solid #333 !important;
		}

 

The iOS-like theme code (app-ios.css)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* iOS Default */
a[data-role="button"][data-theme="reset"].ios .ui-btn-inner {
    border: 1px solid rgba(0,0,0, 0.4);
    text-shadow: 0 -1px 0 rgba(0, 0, 0, .5);
    background: -webkit-linear-gradient(top, #89A0BE 0%,#5877A2 50%,#486A9A 51%,#4A6C9B 100%);
    }
 
/* iOS Red */
a[data-role="button"][data-theme="reset"].ios.red .ui-btn-inner {
    background: -webkit-linear-gradient(top, #DC7679 0%,#DC7679 49%,#CD2A27 50%,#C92A29 100%);
    }
 
/* iOS Blue */
a[data-role="button"][data-theme="reset"].ios.blue .ui-btn-inner {
    background: -webkit-linear-gradient(top, #376FE0 0%,#376FE0 49%,#2361DE 50%,#2463DE 100%);
    }
 
/* iOS Black */
a[data-role="button"][data-theme="reset"].ios.black .ui-btn-inner {
    background: -webkit-linear-gradient(top, #6A6A6A 0%,#313131 49%,black 50%,black 100%);
    }
/* iOS Default */
a[data-role="button"][data-theme="reset"].ios .ui-btn-inner {
    border: 1px solid rgba(0,0,0, 0.4);
	text-shadow: 0 -1px 0 rgba(0, 0, 0, .5);
    background: -webkit-linear-gradient(top, #89A0BE 0%,#5877A2 50%,#486A9A 51%,#4A6C9B 100%);
	}

/* iOS Red */
a[data-role="button"][data-theme="reset"].ios.red .ui-btn-inner {
    background: -webkit-linear-gradient(top, #DC7679 0%,#DC7679 49%,#CD2A27 50%,#C92A29 100%);
	}

/* iOS Blue */
a[data-role="button"][data-theme="reset"].ios.blue .ui-btn-inner {
    background: -webkit-linear-gradient(top, #376FE0 0%,#376FE0 49%,#2361DE 50%,#2463DE 100%);
	}

/* iOS Black */
a[data-role="button"][data-theme="reset"].ios.black .ui-btn-inner {
    background: -webkit-linear-gradient(top, #6A6A6A 0%,#313131 49%,black 50%,black 100%);
	}

jQuery Mobile Buttons – iOS Theme

 

Adding elements using CSS

Imagine that you need to make a one time change to a button. This is an interesting scenario. The following example show how to add a “new” badge to a button using CSS pseudo selectors to modify the HTML structure:

 

Inline cose to accommodate the badge

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<!-- HTML code - iOS Default + badge -->
<a href="#another-page"
    data-role="button"
    data-theme="reset"
    class="ios app-btn-new-badge">iOS Default
</a>
<!-- CSS code for the badge element -->
<style type="text/css">
    .app-btn-new-badge .ui-btn-inner:before {
        content: 'new';
        position: absolute;
        box-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
        float: right;
        width: 30px;
        height: 30px;
        right: 0px;
        top: 0px;
        margin-right: -15px;
        margin-top:  -15px;
        background-color: red;
        background-image: -webkit-linear-gradient(top, #f7847e 0%,#f9363d 49%,#e8100e 50%,#c30910 100%);
        color: white;
        font-size: 12px;
        font-weight: bold;
        line-height: 30px;
        border: black;
        border-radius: 30px;
        border: solid 2px white;
        z-index: 2;
        }
</style>
<!-- HTML code - iOS Default + badge -->
<a href="#another-page"
    data-role="button"
    data-theme="reset"
    class="ios app-btn-new-badge">iOS Default
</a>
<!-- CSS code for the badge element -->
<style type="text/css">
	.app-btn-new-badge .ui-btn-inner:before {
		content: 'new';
		position: absolute;
		box-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
		float: right;
		width: 30px;
		height: 30px;
		right: 0px;
		top: 0px;
		margin-right: -15px;
		margin-top:  -15px;
		background-color: red;
		background-image: -webkit-linear-gradient(top, #f7847e 0%,#f9363d 49%,#e8100e 50%,#c30910 100%);
		color: white;
		font-size: 12px;
		font-weight: bold;
		line-height: 30px;
		border: black;
		border-radius: 30px;
		border: solid 2px white;
		z-index: 2;
		}
</style>

jQuery Mobile Button + Badge

 

Adding elements using Javascript

There are scenarios where you might need to create a more complex structure inside the button. In the article How to Make an iPhone Back Button in jQuery Mobile we show how to add a DIV and  a SPAN element inside an jQuery Mobile button (<div><span></span></div>).

jQuery Mobile - iOS-like back button

 

In order to create the point for the button we added a SPAN tag that takes a linear gradient from the upper left corner to the lower right corner. The SPAN tag is rotated 45 degrees and the DIV tag is scaled to make the shape of a diamond. The new elements are added from a callback function that is trigger when the document loads:

Adding elements using a callback function

1
2
3
4
5
6
$(document).ready(function(){
    // make sure we only add the point the back buttons
    var backButton = $('a[data-theme="app-ios"]').filter('[data-rel="back"]');
    backButton.find('.ui-icon').remove(); // remove icon (if it's found)
    backButton.append('<div class="ios-tip"><span>&nbsp;</span></div>');
});
$(document).ready(function(){
    // make sure we only add the point the back buttons
    var backButton = $('a[data-theme="app-ios"]').filter('[data-rel="back"]');
    backButton.find('.ui-icon').remove(); // remove icon (if it's found)
    backButton.append('<div class="ios-tip"><span>&nbsp;</span></div>');
});

 

If you choose to use Javascript to modify the structure of a button, be aware that your mobile application might load other pages and your code might have to be executed again to make sure that the newly loaded page inherit the changes.

 

Icon-only buttons

If you just want to get rid of the button background and text all together, you apply the reset theme and focus on the icon. The example below uses a standard navigation bar but removes the background, borders, and text label from the button.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<!-- HTML code - icon-only buttons -->
<div data-role="navbar">
    <ul>
        <li>
            <a href="#dashboard"
                data-role="button"
                data-theme="reset"
                data-icon="dashboard"
                class="ios app-theme-none notext">Dashboard
            </a>
        </li>
        <li>
            <a href="#location"
                data-role="button"
                data-theme="reset"
                data-icon="location"
                class="ios app-theme-none notext">Location
            </a>
        </li>
        <li>
            <a href="#radar"
                data-role="button"
                data-theme="reset"
                data-icon="radar"
                class="ios app-theme-none notext">Radar
            </a>
        </li>
    </ul>
</div>        
 
<!-- CSS code -->
<style type="text/css">
/* setup icon images */
.ui-icon-dashboard,
.ui-icon-location,
.ui-icon-radar {
    width:28px;
    height: 28px;
    background-color: rgba(0, 0, 0, 0);
    border: none;
    box-shadow: none;
    }
.ui-icon-dashboard  {background-image: url('dashboard.png');}
.ui-icon-location {background-image: url('radar.png');}
.ui-icon-radar {background-image: url('location.png');}
</style>
<!-- HTML code - icon-only buttons -->
<div data-role="navbar">
	<ul>
		<li>
			<a href="#dashboard"
			    data-role="button"
			    data-theme="reset"
			    data-icon="dashboard"
			    class="ios app-theme-none notext">Dashboard
			</a>
		</li>
		<li>
			<a href="#location"
			    data-role="button"
			    data-theme="reset"
			    data-icon="location"
			    class="ios app-theme-none notext">Location
			</a>
		</li>
		<li>
			<a href="#radar"
			    data-role="button"
			    data-theme="reset"
			    data-icon="radar"
			    class="ios app-theme-none notext">Radar
			</a>
		</li>
	</ul>
</div>        

<!-- CSS code -->
<style type="text/css">
/* setup icon images */
.ui-icon-dashboard,
.ui-icon-location,
.ui-icon-radar {
	width:28px;
	height: 28px;
    background-color: rgba(0, 0, 0, 0);
    border: none;
    box-shadow: none;
	}
.ui-icon-dashboard 	{background-image: url('dashboard.png');}
.ui-icon-location {background-image: url('radar.png');}
.ui-icon-radar {background-image: url('location.png');}
</style>

jQuery Mobile Buttons - Icon-only

 

Targeting buttons by context

Finally, remember that the look-and-feel of a button will change depending on where the button is located. For instance, buttons located inside a controlgroup will be connected so you will have to write additional CSS rules to acknowledge different context. In the case of the a crontrolgroup the main element inherits the CSS class ui-controlgroup. You can use this class name as your starting point in your CSS selector:

1
2
3
.ui-controlgroup a[data-role="button"][data-theme="reset"] .ui-btn-text {
    // do something with the text
    }
.ui-controlgroup a[data-role="button"][data-theme="reset"] .ui-btn-text {
	// do something with the text
	}

 

Change the text color only if the button is inside a controlgroup

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
        <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script>
        <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" />
        <link rel="stylesheet" href="app-reset.css" />
        <link rel="stylesheet" href="app-theme-ios.css" />
        <title>Segmented Buttons</title>
    </head>
    <body>
        <style type="text/css">
        /* change the color of the text only if the button is inside a controlgroup */
        .ui-controlgroup a[data-role="button"][data-theme="reset"] .ui-btn-text {
            color: yellow;
            }
 
        </style>
        <div data-role="page" id="ios-theme">
            <div data-theme="b" data-role="header" style="text-align: center; padding-top: 7px;">
                <div data-role="controlgroup" data-type="horizontal">
                    <a href="#" data-role="button" data-theme="reset" data-icon="star"    data-iconpos="left" class="ios">Star</a>
                    <a href="#" data-role="button" data-theme="reset" data-icon="gear"    data-iconpos="left" class="ios">Gear</a>
                    <a href="#" data-role="button" data-theme="reset" data-icon="refresh" data-iconpos="left" class="ios">Refresh</a>
                </div>
            </div><!-- /header -->
            <div data-role="content">
                <div data-role="controlgroup" data-type="horizontal">
                    <a href="#" data-role="button" data-theme="reset" data-icon="star"    data-iconpos="left" class="ios">Star</a>
                    <a href="#" data-role="button" data-theme="reset" data-icon="gear"    data-iconpos="left" class="ios">Gear</a>
                    <a href="#" data-role="button" data-theme="reset" data-icon="refresh" data-iconpos="left" class="ios">Refresh</a>
                </div>  
 
                <a href="#" data-role="button" data-theme="a" data-icon="star"    data-iconpos="left" class="ios">Star</a>
                <a href="#" data-role="button" data-theme="a" data-icon="gear"    data-iconpos="left" class="ios">Gear</a>
                <a href="#" data-role="button" data-theme="a" data-icon="refresh" data-iconpos="left" class="ios">Refresh</a>
            </div><!-- /content -->
        </div><!-- /page -->
    </body>
</html>
<!DOCTYPE html>
<html>
	<head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
        <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script>
        <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" />
        <link rel="stylesheet" href="app-reset.css" />
        <link rel="stylesheet" href="app-theme-ios.css" />
		<title>Segmented Buttons</title>
	</head>
	<body>
		<style type="text/css">
		/* change the color of the text only if the button is inside a controlgroup */
		.ui-controlgroup a[data-role="button"][data-theme="reset"] .ui-btn-text {
			color: yellow;
			}

		</style>
		<div data-role="page" id="ios-theme">
		    <div data-theme="b" data-role="header" style="text-align: center; padding-top: 7px;">
		        <div data-role="controlgroup" data-type="horizontal">
					<a href="#" data-role="button" data-theme="reset" data-icon="star"    data-iconpos="left" class="ios">Star</a>
					<a href="#" data-role="button" data-theme="reset" data-icon="gear"    data-iconpos="left" class="ios">Gear</a>
					<a href="#" data-role="button" data-theme="reset" data-icon="refresh" data-iconpos="left" class="ios">Refresh</a>
				</div>
		    </div><!-- /header -->
		    <div data-role="content">
				<div data-role="controlgroup" data-type="horizontal">
					<a href="#" data-role="button" data-theme="reset" data-icon="star"    data-iconpos="left" class="ios">Star</a>
					<a href="#" data-role="button" data-theme="reset" data-icon="gear"    data-iconpos="left" class="ios">Gear</a>
					<a href="#" data-role="button" data-theme="reset" data-icon="refresh" data-iconpos="left" class="ios">Refresh</a>
				</div>  

				<a href="#" data-role="button" data-theme="a" data-icon="star"    data-iconpos="left" class="ios">Star</a>
				<a href="#" data-role="button" data-theme="a" data-icon="gear"    data-iconpos="left" class="ios">Gear</a>
				<a href="#" data-role="button" data-theme="a" data-icon="refresh" data-iconpos="left" class="ios">Refresh</a>
		    </div><!-- /content -->
		</div><!-- /page -->
	</body>
</html>

jQuery Mobile Button - Controlgroup

 

Conclusion

Throughout this article we discussed how to customize standard jQuery Mobile buttons in ways that will give you absolute control over the look-and-feel. In some cases you might feel that it is easier to simply turn your custom button into an image and stick it inside an “a” tag. You might be right. It is easier, but not scalable. From the visual viewpoint, today’s web is more dynamic. The screen size and resolution of the devices are constantly evolving. The application layout is becoming more responsive. To accommodate for all this changes you need to pick a strategy that is efficient, flexible, and more important, pain-free. Addressing elements customization using CSS while preserving the original HTML structure might not be the easiest way, but it is certainly more scalable path.


Click HERE to download the source code and basic examples showing how to customize jQuery Mobile Buttons.

Advanced jQuery Custom Buttons

Download Custom Buttons Example