Dijit Themes, Buttons, and Textboxes

In this tutorial, we will show you the basics of creating and using simple form elements using Dijit—including how to set up a Dijit theme for your web application.

  • Difficulty: Beginner
  • Dojo Version: 1.7

Introduction

Dijit, the Dojo Toolkit's UI framework, contains a comprehensive set of widgets to help you rapidly develop web applications. Central to most web applications are form elements—simple widgets that allow for user input, usually to be transmitted to a server for additional handling. Dijit has quite a few form-based widgets for you to work with, including buttons, textboxes, validating textboxes, select-based elements, sliders and more.

In addition, Dijit includes a theming framework that allows a user to define—in detail, if needed—the visual aspects of all Dijits. This theming is simple to use, and Dijit includes four themes to choose from: Claro, Tundra, Soria, and Nihilo.

Using a Dijit theme

To use a Dijit theme, two things are needed: a reference to the main theme CSS file, and the setting of a CSS class on the body element of your page, like so:

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>Hello Dijit!</title>
	<!-- load Dojo -->
	<link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/dojo/1.7.7/dijit/themes/claro/claro.css">
	<script src="//ajax.googleapis.com/ajax/libs/dojo/1.7.7/dojo/dojo.js" data-dojo-config="isDebug: true, async: true, parseOnLoad: true"></script>
</head>
<!-- set the claro class on our body element -->
<body class="claro">
	<h1 id="greeting">Hello</h1>
</body>
</html>

To avoid any flash of unstyled content due to delays in CSS downloading, you should always include the theme's CSS file before loading dojo.js.

The actual CSS class names for each available theme are claro, tundra, soria and nihilo. A typical setup for a Dijit-based application is to include this class on the body element, so that all Dijits on a page are consistently styled.

You can restrict the Dijit theme to only small portions of a page; you do this by applying the CSS class of the theme to a block-level element, such as a div. However, keep in mind that any popup-based widget (or widgets that use popups, such as dijit/form/ComboButton, dijit/form/DropDownButton, and dijit/form/Select) create and place the DOM structure for the popup as a direct child of the body element—which means that your theme will not be applied to the popup.

Now that we have a typical Dijit-based page set up, let's go ahead and start including the form widgets we'd like to use.

Buttons in Dijit

Probably the most basic widget in any toolkit is a button; this type of user input allows a user to trigger an action, such as submitting a form or resetting the values on a form. Dijit's implementation is pretty simple:

<body class="claro">
	<button id="btn" data-dojo-type="dijit.form.Button"
		data-dojo-props="
			onClick:function(){ console.log('First button was clicked!'); }">
		Click Me!
	</button>
	<script>
		// load requirements for declarative widgets in page content
		require(["dijit/form/Button", "dojo/parser", "dojo/domReady!"]);
	</script>
</body>
<body class="claro">
	<button id="btn"></button>
	<script>
		require(["dijit/form/Button", "dojo/domReady!"], function(Button) {
			var button = new Button({
				label: "Click Me!",
				onClick: function(){ console.log("First button was clicked!"); }
			}, "btn");
			button.startup();
		});
	</script>
</body>

Don't forget: if you are going to define widgets declaratively, make sure you add "parseOnLoad: true" to the data-dojo-config attribute on the script tag that includes dojo.js on the page. Furthermore, it is necessary to explicitly require(["dojo/parser"]) when you intend to use it.

As you can see, creating a dijit/form/Button [ref | api] is pretty simple, and behaves very much like a regular HTML button element. Dijit buttons also support using an image or image sprite in conjunction with a label—or even the image alone—like so:

<body class="claro">
	<button id="btn2" data-dojo-type="dijit.form.Button"
		data-dojo-props="
			iconClass:'dijitIconNewTask',
			showLabel:false,
			onClick:function(){ console.log('Second button was clicked!'); }">
		Click Me!
	</button>
	<script>
		// load requirements for declarative widgets in page content
		require(["dojo/parser", "dijit/form/Button", "dojo/domReady!"]);
	</script>
</body>
<body class="claro">
	<div>
		<button id="btn2"></button>
	</div>
	<script>
		require(["dijit/form/Button", "dojo/domReady!"], function(Button) {
			var button2 = new Button({
				iconClass:"dijitIconNewTask",
				showLabel:false,
				label: "Click Me!", // analogous to title when showLabel is false
				onClick: function(){ console.log("Second button was clicked!"); }
			}, "btn2");

			button2.startup();
		});
	</script>
</body>
View Declarative Demo View Programmatic Demo

Several widget properties are employed in the example above:

  • iconClass: indicates what CSS class to use (to apply an image sprite)
  • showLabel: determines whether to show any text in the button
  • title: sets the value of the HTML title attribute on the rendered DOM node of the widget
  • label: in programmatic usage, this indicates the content of the button label; declaratively, this is specified via the content (innerHTML) of the element representing the widget

When using a dijit/form/Button inside a form (or perhaps even a dijit/form/Form), you can add type:"submit" or type:"reset" to your button's properties (via data-dojo-props declaratively, or in the object passed to the constructor programmatically) to achieve the same behavior as a native HTML button of the same type.

Even in the simplest usages of dijit/form/Button, it is good practice to specify type:"button"—in its absence, the button would default its type to submit. While this normally wouldn't be a problem outside of a form, older versions of IE wrap buttons in a form anyway—which can ultimately lead to confusing behavior.

Dijit also includes three other button widgets:

  • dijit/form/ToggleButton: a button that maintains an on/off state [ref | api]
  • dijit/form/DropDownButton: a button designed to show a popup widget (such as a menu) when clicked [ref | api]
  • dijit/form/ComboButton: like a dijit/form/Button and a dijit/form/DropDownButton combined—the primary region can perform an action when clicked, and the drop-down region can show a popup widget [ref | api]

The following example shows these three widgets in action:

<body class="claro">
	<button id="toggle" data-dojo-type="dijit.form.ToggleButton"
		data-dojo-props="iconClass:'dijitCheckBoxIcon', checked:true">
		Toggle
	</button>

	<div id="combo" data-dojo-type="dijit.form.ComboButton"
		data-dojo-props="
			optionsTitle:'Save Options',
			iconClass:'dijitIconFile',
			onClick:function(){ console.log('Clicked ComboButton'); }">
		<span>Combo</span>
		<div id="saveMenu" data-dojo-type="dijit.Menu">
			<div data-dojo-type="dijit.MenuItem"
				data-dojo-props="
					iconClass:'dijitEditorIcon dijitEditorIconSave',
					onClick:function(){ console.log('Save'); }">
				Save
			</div>
			<div data-dojo-type="dijit.MenuItem"
				data-dojo-props="onClick:function(){ console.log('Save As'); }">
				Save As
			</div>
		</div>
	</div>

	<div id="dropDown" data-dojo-type="dijit.form.DropDownButton"
		data-dojo-props="iconClass:'dijitIconApplication'">
		<span>DropDown</span>
		<div data-dojo-type="dijit.TooltipDialog">
			This is a TooltipDialog. You could even put a form in here!
		</div>
	</div>

	<script>
		// load requirements for declarative widgets in page content
		require(["dijit/form/ToggleButton", "dijit/form/ComboButton", "dijit/Menu", "dijit/MenuItem", "dijit/form/DropDownButton", "dijit/TooltipDialog", "dojo/parser"]);
	</script>
</body>
<body class="claro">
	<button id="toggle"></button>
	<button id="combo"></button>
	<button id="dropDown"></button>
	<script>
		require(["dijit/form/ToggleButton", "dijit/form/ComboButton", "dijit/Menu", "dijit/MenuItem", "dijit/form/DropDownButton", "dijit/TooltipDialog"], function(ToggleButton, ComboButton, Menu, MenuItem, DropDownButton, TooltipDialog) {

			var toggleButton = new ToggleButton({
				iconClass: "dijitCheckBoxIcon",
				label: "Toggle",
				checked: true
			}, "toggle");
			toggleButton.startup();

			var menu = new Menu({
				id: "saveMenu"
			});
			var menuItem1 = new MenuItem({
				label: "Save",
				iconClass: "dijitEditorIcon dijitEditorIconSave",
				onClick: function() { console.log("Save"); }
			});
			var menuItem2 = new MenuItem({
				label: "Save As",
				onClick: function() { console.log("Save As"); }
			});
			menu.addChild(menuItem1);
			menu.addChild(menuItem2);
			var comboButton = new ComboButton({
				optionsTitle: "Save Options",
				iconClass: "dijitIconFile",
				label: "Combo",
				dropDown: menu,
				onClick:function(){ console.log("Clicked ComboButton"); }
			}, "combo");
			comboButton.startup();
			menu.startup(); // this also starts up its child MenuItems

			var tooltip = new TooltipDialog({
				content: "This is a TooltipDialog. You could even put a form in here!"
			});
			var dropDownButton = new DropDownButton({
				iconClass: "dijitIconApplication",
				label: "DropDown",
				dropDown: tooltip
			}, "dropDown");
			dropDownButton.startup();
			tooltip.startup();

		});
	</script>
</body>
	
View Declarative Demo View Programmatic Demo

Notice that dijit/form/ComboButton and dijit/form/DropDownButton cooperate with popup widgets, such as dijit/Menu, dijit/TooltipDialog, and dijit/ColorPalette.

The Dijit TextBox Family

No UI toolkit would be complete without some form of basic user input, and Dijit is no exception. Within the dijit/form namespace, there are a number of textbox-based widgets, each with a specific purpose:

  • dijit/form/TextBox: a basic textbox [ref | api]
  • dijit/form/SimpleTextarea: a basic textarea, for large text input [ref | api]
  • dijit/form/ValidationTextBox: a textbox with basic validation abilities, which can be further customized [ref | api]
  • dijit/form/NumberTextBox: a textbox that ensures the input is numeric [ref | api]
  • dijit/form/DateTextBox: a textbox that includes a popup calendar [ref | api]
  • dijit/form/TimeTextBox: a textbox that includes a popup time-picker [ref | api]
  • dijit/form/CurrencyTextBox: an extension of dijit/form/NumberTextBox with additional considerations for localized currency [ref | api]
  • dijit/form/NumberSpinner: an extension of dijit/form/NumberTextBox providing buttons and keybindings for incrementally changing the value [ref | api]
  • dijit/form/Textarea: an extension of dijit/form/SimpleTextarea which dynamically increases or decreases its height based on the amount of content inside [ref | api]

As we mentioned before, you can apply a theme to just portions of your page—but if you plan on using either dijit/form/DateTextBox or dijit/form/TimeTextBox, you will need to apply your theme CSS class to the body element of the page.

In the next example, we create instances of dijit/form/TextBox and dijit/form/SimpleTextarea. This should feel quite familiar after creating the buttons above.

<body class="claro">
	<div>
		<label for="text">Name:</label>
		<input id="text" data-dojo-type="dijit.form.TextBox"
			data-dojo-props="placeHolder:'Enter text here.'">
	</div>
	<div>
		<label for="textarea">Description:</label>
		<textarea id="textarea" rows="5" cols="50"
			data-dojo-type="dijit.form.SimpleTextarea"
			data-dojo-props="
				onFocus:function(){ console.log('textarea focus handler') },
				onBlur:function(){ console.log('textarea blur handler') },
				selectOnClick:true
		">This is a sample SimpleTextarea.</textarea>
	</div>
	<script>
		// load requirements for declarative widgets in page content
		require(["dijit/form/TextBox", "dijit/form/SimpleTextarea", "dojo/parser", "dojo/domReady!"]);
	</script>
</body>
<body class="claro">
	<div>
		<label for="text">Name:</label>
		<input id="text">
	</div>
	<div>
		<label for="textarea">Description:</label>
		<textarea id="textarea"></textarea>
	</div>
	<script>
		require(["dijit/form/TextBox", "dijit/form/SimpleTextarea", "dojo/domReady!"], function(TextBox, SimpleTextarea) {

			var textbox = new TextBox({
				placeHolder: "Enter text here."
			}, "text");
			textbox.startup();

			var textarea = new SimpleTextarea({
				rows: 5,
				cols: 50,
				onFocus: function(){ console.log("textarea focus handler"); },
				onBlur: function(){ console.log("textarea blur handler"); },
				selectOnClick: true,
				value: "This is a sample SimpleTextarea."
			}, "textarea");
			textarea.startup();
		});
	</script>
</body>
	
View Declarative Demo View Programmatic Demo

The following example demonstrates basic functionality of dijit/form/NumberTextBox, dijit/form/CurrencyTextBox, dijit/form/TimeTextBox, and dijit/form/DateTextBox.

<body class="claro">
	<div>
		<label for="number">Age:</label>
		<input id="number" type="text" value="54" required="true" data-dojo-type="dijit.form.NumberTextBox">
	</div>
	<div>
		<label for="currency">Annual Salary:</label>
			<input id="currency" value="54775.53" required="true"
				data-dojo-type="dijit.form.CurrencyTextBox"
				data-dojo-props="
					constraints:{fractional:true},
					currency:'USD',
					invalidMessage:'Invalid amount. Cents are mandatory.'">
	</div>
	<div>
		<label for="time">Start Time:</label>
		<input id="time" required="true"
			data-dojo-type="dijit.form.TimeTextBox"
			data-dojo-props="
				constraints: {
					timePattern: 'HH:mm:ss',
					clickableIncrement: 'T00:15:00',
					visibleIncrement: 'T00:15:00',
					visibleRange: 'T01:00:00'
				},
				invalidMessage:'Invalid time.'">
	</div>
	<div>
		<label for="date">Start Date:</label>
			<input id="date" value="2011-09-15" data-dojo-type="dijit.form.DateTextBox">
	</div>
	<script>
		// load requirements for declarative widgets in page content
		require(["dijit/form/NumberTextBox", "dijit/form/CurrencyTextBox", "dijit/form/TimeTextBox", "dijit/form/DateTextBox", "dojo/domReady!", "dojo/parser"]);
	</script>
</body>
<body class="claro">
	<div>
		<label for="number">Age:</label>
		<input id="number">
	</div>
	<div>
		<label for="currency">Annual Salary:</label>
		<input id="currency">
	</div>
	<div>
		<label for="time">Start Time:</label>
		<input id="time">
	</div>
	<div>
		<label for="date">Start Date:</label>
		<input id="date">
	</div>
	<script>
		require(["dijit/form/NumberTextBox", "dijit/form/CurrencyTextBox", "dijit/form/TimeTextBox", "dijit/form/DateTextBox", "dojo/domReady!"], function(NumberTextBox, CurrencyTextBox, TimeTextBox, DateTextBox) {
			var number = new NumberTextBox({
				value: 54,
				required: true
			}, "number");
			number.startup();

			var currency = new CurrencyTextBox({
				value:54775.53,
				required:true,
				constraints:{fractional:true},
				currency:"USD",
				invalidMessage:"Invalid amount. Cents are mandatory."
			}, "currency");
			currency.startup();

			var time = new TimeTextBox({
				constraints: {
					timePattern: "HH:mm:ss",
					clickableIncrement: "T00:15:00",
					visibleIncrement: "T00:15:00",
					visibleRange: "T01:00:00"
				},
				invalidMessage:"Invalid time."
			},"time");
			time.startup();

			var date = new DateTextBox({
				value: new Date(2011, 8, 15)
			}, "date");
			date.startup();
		});
	</script>
</body>
	
View Declarative Demo View Programmatic Demo

Again, if you are going to define your widgets declaratively, don't forget to require dojo/parser, and add "parseOnLoad: true" to the data-dojo-config attribute on the script tag for dojo.js.

Conclusion

In this tutorial, we've shown you how Dijit gives you many variations on two basic input elements for any kind of user interface: buttons and textboxes. In addition, we've shown you the basics of including a CSS-based theme so that your user interface is both beautiful and functional.

In addition to the API and Reference Guide documentation, there are test pages within the Dojo Toolkit SDK distribution which test various configurations of widgets. Tests for button and textbox widgets can be found online, or in the dijit/tests/form folder of your local copy.

Error in the tutorial? Can’t find what you are looking for? Let us know!