Interface patterns
The staff interface to Koha is complex, with over five hundred templates which are used to display an even greater number of distinct pages. With so many different kinds of interfaces it can be hard to stay consistent. There are, however, some established patterns which template creators and editors try to follow. This document elaborates on these.
The header
Almost every page in the staff client includes the same elements at the top of the page, all contained within a region we can call the header, highlighted in this screenshot:
At the top of the header is the header menu, a fixed set of menu items on the left and user/login information on the right:
While it is possible to customize this menu by adding additional links, the contents of the menu are not context-sensitive, staying the same no matter what page you're on.
The header search
Below the header menu is a region common to almost all staff client pages which contains the Koha logo and the header search form:
The header search form contains two or more different search options depending on where you are in the staff client. On pages for which there is no relevant search, a default set of options should be used: Check out, Check in, and Search the catalog (currently in an include called circ-search.inc). Other sections of the staff client show a different set of search options based on search tools available for that section. On patron related pages a different patron search option is included:
On cataloging pages the assumption is made that circulation functions are less important than a search specific to the cataloging module:
On the system preferences page a search of system preferences is offered:
Note that one of the goals in selecting which searches are offered is to avoid ambiguity. The cataloging search form omits the standard catalog search because the focus is the cataloging search.
"Check out" and "Catalog search" are often the fallback options for pages which include another module-specific search as the primary search option, but they are not required. Other sections omit those options in favor of a set of completely module-specific options. For instance in Acquisitions where "Vendor Search" and "Orders Search" are the only options.
In practice the primary module-specific search is usually placed first and highlighted. In some cases you might find the same set of search options (e.g. Check out, Check in, and Search the catalog) but find that different options are highlighted by default on different pages: Check out is highlighted on circulation-related pages, but Search the catalog is highlighted on some pages, like Tools, where the search form is in not in a "module-specific" state.
Another factor to consider when designing a header search form is simplicity. In the past we have tried to limit the number of search options to three options which seem most relevant to module the user is in. This has expanded to four in some cases (like the patron module). Current practice in Koha's template design is to make the choice to eliminate the least relevant default search option in order to make room for a module-specific search option: "Check in" is omitted in favor of "Search system preferences" in the system preferences interface.
Breadcrumbs
Below the header region is the breadcrumbs menu. The breadcrumbs menu provides two functions: First, it orients the user to their "location" in the staff client. It should show where they are (with a repetition of the page title) and what module they're in. In some cases it is possible to offer breadcrumb links to intermediate steps in the user's process. In these cases the menu fulfills the second function, offering users direct links to other pages which may be previous pages in a linear workflow or other relevant pages in the module.
The breadcrumbs does not (and cannot) show the user exactly the links they have taken to arrive at any particular page. Since breadcrumbs are hard-coded for each template, an assumption must be made about a logical hierarchy of links to offer. In acquisitions, the user may have used an order search to find a particular basket, but the breadcrumbs can't know to show a link back to the order search when viewing the basket. Instead it shows links to a hierarchy of pages related to the basket:
When designing breadcrumbs keep in mind paths the user might want to take which are not offered by any other navigation in the interface. Improvements to breadcrumbs menus are often made based on specific usage patterns which are not accommodated.
Breadcrumb navigation uses Bootstrap markup. In order to abstract the specific elements of the markup and ease the process of upgrading Bootstrap versions, a system of Template::Toolkit WRAPPER directives are used. A typical example might look like this:
[% WRAPPER breadcrumbs %]
[% Home breadcrumb automatically included %]
[% WRAPPER breadcrumb_item %]
<a href="/cgi-bin/koha/module/module-home.pl"> Module </a>
[% END %]
[% IF ( op == 'add_form' || op == 'delete_confirm' ) %]
[% WRAPPER breadcrumb_item %]
<a href="/cgi-bin/koha/module/page.pl"> Module page </a>
[% END %]
[% END %]
[% IF op == 'add_form' %]
[% WRAPPER breadcrumb_item bc_active = 1 %]
<span>Add form</span>
[% END %]
[% ELSIF op == 'delete_confirm' %]
[% WRAPPER breadcrumb_item bc_active = 1 %]
<span>Confirm deletion</span>
[% END %]
[% ELSE %]
[% WRAPPER breadcrumb_item bc_active = 1 %]
<span>Module page</span>
[% END %]
[% END #/IF op = add_form %]
[% END #/ WRAPPER breadcrumbs %]
When the template is rendered in the browser the breadcrumb elements are wrapped in the correct Bootstrap breadcrumb menu markup:
<nav id="breadcrumbs" aria-label="Breadcrumb" class="breadcrumb">
<ol>
<li>
<a href="/cgi-bin/koha/mainpage.pl">Home</a>
</li>
<li>
<a href="/cgi-bin/koha/admin/admin-home.pl">Administration</a>
</li>
<li>
<a href="/cgi-bin/koha/admin/cities.pl">Cities</a>
</li>
<li>
<a href="#" aria-current="page">
<span>New city</span>
</a>
</li>
</ol>
</nav>
Note that some elements of the template show text wrapped in tags. This is done to ease template translation.
Errors and messages
When Koha needs to communicate something directly to the user it usually takes one of two forms: an informational message or an error message. Each type is used for specific categories of communications, and each using Bootstrap alert styles.
Informational messages
When Koha needs to communicate information to the user about a transaction, status, or some other non-critical event the information should be displayed using the message style. The markup looks like this:
<div class="alert alert-info">
Informational message here
</div>
The "alert" class gives the message its basic orientation and size. The "alert-info" class adds the color which distinguishes it from an error message. Informational messages convey information to the user which does not require action. An informational message doesn't ask the user a question.
Examples
Error messages
When Koha needs to ask the user a question or block an action an error message should be used. Error messages should be used when Koha requires that the user stop and make a decision or when Koha must stop an operation that the user has initiated. Error message markup looks like this:
<div class="alert alert-warning">
Error message here
</div>
Again, the "alert" class gives the message box the same basic style as the information message, but the "alert-warning" class adds a style specific to this type of message.
Examples:
Usage
As defined above an information message conveys "non-blocking" information to the user while error messages display information which blocks an operation or requires the user's input. Not all instances of each type of message are currently consistent with these guidelines, so the templates have room for improvement.
The screenshot snippet below is a good example of the two types of messages displayed in combination:
These messages appeared in a situation where a number of things were happening at once. The "Cannot place hold" error message conveys the blocking information: that the hold cannot be placed. The other, informational messages convey information which may be relevant to the user but which does not interfere with the user being able to complete the task at hand.
Views and Actions
Many of the interactions in the Koha staff client can be divided up into two very general categories: Views and actions. The categories determine how the action is displayed in the interface: in a sidebar tab or in a toolbar.
- Views are ways of looking at information about a record.
- Actions are things you can do to a record.
These distinctions are the best defined when looking at patrons or bibliographic records.
Patrons |
Bibliographic Records | ||
---|---|---|---|
View |
Actions |
View |
Actions |
Details |
Edit |
Normal |
New |
Fines |
Change password |
MARC |
Edit |
Circ history |
Duplicate |
Items |
Save |
Messages |
Print |
Holds |
Print |
Here's a highlighted screenshot as an example:
The distinction between views and actions is a good one to keep in mind when deciding whether to use a link or a button for certain types of interaction. If the interaction can fit into one of those two categories you can group them with existing options.
Page layouts
The Koha staff client uses Bootstrap grids, "a responsive, mobile first fluid grid system that appropriately scales up to 12 columns as the device or viewport size increases."
Common page layouts
Bootstrap grids offer a wide variety of options for page layouts. Still, there are a number of common layouts currently in use in the staff client templates.
Fluid-width page with adaptive left-hand sidebar
Examples: Circulation, Patrons, Search results
<div class="main container-fluid">
<div class="row">
<div class="col-md-10 order-md-2 order-sm-1">
<main>
</main>
</div>
<div class="col-md-2 order-sm-2 order-md-1">
<aside>
</aside>
</div>
</div>
</div>
Fluid centered page with no sidebars
Examples: Patron entry, Advanced search, the basic MARC editor
<div class="main container-fluid">
<div class="row">
<div class="col-md-10 offset-md-1 col-lg-8 offset-lg-2">
<main>
</main>
</div> <!-- .col-md-10.offset-md-1.col-lg-8.offset-lg-2 -->
</div>
</div>
The matching "-offset-2" class suffixes allow us to keep the source order of page elements: Main body first, sidebar second.
Fluid-width page with no sidebar
Examples: About page, Holds awaiting pickup
<div class="main container-fluid">
<div class="row">
<div class="col-md-12">
<main>
<!-- Main body of the page -->
</main>
</div> <!-- /.col-md-12 -->
</div> <!-- /.row -->
</div> <!-- /.main.container-fluid -->
Grids within pages
Bootstrap grids can be nested within each other. For example, to add a nested 3-column grid in the body of a page with a left-hand sidebar, add a div with a "row" class:
<div class="main container-fluid">
<div class="row">
<div class="col-md-10 order-md-2 order-sm-1">
<main>
<div class="row">
<div class="col-12 col-sm-4">
</div>
<div class="col-12 col-sm-4">
</div>
<div class="col-12 col-sm-4">
</div>
</div>
</main>
</div>
<div class="col-md-2 order-sm-2 order-md-1">
<aside>
</aside>
</div>
</div>
</div>
Common interface patterns
Many interfaces in Koha follow a similar pattern where data is shown initially in a table. Links are provided for edit and delete views. A toolbar provides additional actions like "New."
The data list view
Using Administration -> Cities and towns as an example, the initial view shows all existing cities in a table:
Note the order of the elements:
- Toolbar
- Heading
- Table
If there are more than two "actions" available in the data list view those actions might be combined in a menu. For example, in Administration -> Funds:
If there is no data to list, a message will be shown:
In cases like this where the user has the ability to create a new instance of whatever kind of record is to be displayed, a link to the "New" entry form can be displayed in the message.
The 'New' entry form
The data list view will typically include a toolbar with a 'New' button to link to an entry form for creating a new instance of whatever kind of record is being managed. In the Cities and Towns example, this is a new city:
In this view the toolbar is not displayed, because the user is expected to either submit a completed form or choose the 'Cancel' link to abort the process of creating a new entry.
<form class="validated" method="post" action="/cgi-bin/koha/admin/cities.pl">
<input type="hidden" value="add_validate" name="op">
<input type="hidden" value="" name="cityid">
<fieldset class="rows">
<ol>
<li>
<label class="required" for="city_name">City: </label>
<input type="text" class="required" required="required" value="" maxlength="100" size="80" id="city_name" name="city_name">
<span class="required">Required</span>
</li>
<li>
<label for="city_state">State: </label>
<input type="text" value="" maxlength="100" size="80" id="city_state" name="city_state">
</li>
<li>
<label class="required" for="city_zipcode">ZIP/Postal code: </label>
<input type="text" class="required" required="required" value="" maxlength="20" size="20" id="city_zipcode" name="city_zipcode"> <span class="required">Required</span>
</li>
<li>
<label for="city_country">Country: </label>
<input type="text" value="" maxlength="100" size="80" id="city_country" name="city_country">
</li>
</ol>
</fieldset>
<fieldset class="action">
<input type="submit" class="btn btn-primary" value="Submit">
<a href="/cgi-bin/koha/admin/cities.pl" class="cancel">Cancel</a>
</fieldset>
</form>
The 'Edit' entry form
The edit view displays a form for editing one of the items shown in the data list view. The edit view is typically a separate page showing only the edit form:
This view is identical to the 'New' view except that existing data is shown in the form. Note that the first line in the edit form shows data which cannot be edited. Instead of the typical pair of <label> and <input> there is a <span> styled like a label: <span class="label"> followed by the existing data.
Radio buttons and checkboxes
There are two different options for displaying form rows with radio buttons or checkboxes. In the first, the form controls are displayed without a label in the left-hand column:
<fieldset class="rows">
<ol>
<li class="radio">
<label><input type="radio" /> Choice 1</label>
<label><input type="radio" /> Choice 2</label>
<label><input type="radio" /> Choice 3</label>
</li>
</ol>
</fieldset>
In the second version, there is a general label which identifies the choices in the radio buttons or checkboxes:
<fieldset class="rows">
<ol>
<li>
<label>General label:</label>
<label class="radio">
Specific label 1 <input type="radio" />
</label>
<label class="radio">
Specific label 2 <input type="radio" />
</label>
</li>
</ol>
</fieldset>
Deletion confirmation
In some interfaces clicking the "Delete" link or button from the data list view will take you to a deletion confirmation page. On this page an "alert" style dialog asks the user to confirm the deletion:
In other interfaces clicking the "Delete" link will trigger a JavaScript confirmation:
If the user confirms, the entry will be deleted without being taken to a deletion confirmation page.
Buttons
There are several general categories of buttons in the Koha staff client (including link, input and button elements):
Toolbar buttons
Toolbar buttons are styled using Bootstrap classes, often with the inclusion of a Font Awesome icon. The buttons inherit a unique style from the toolbar container.
Buttons in a toolbar might be any combination of inputs, buttons, or links.
A simple example from this toolbar is the "Print" buton:
<a class="btn btn-default" id="printbiblio">
<i class="fa fa-print"></i> Print
</a>
The "btn btn-default" class allows the link or button element inherit the correct style. The <i> element creates the icon.
See Bootstrap documentation for more.
As covered in #Views_and_Actions, Toolbar buttons should be used for "actions," rather than "views."
Dialog buttons
When the staff client interface displays a (non-JavaScript) dialog, as shown in #Deletion_confirmation, buttons have a distinct style which stems from the container they are in. Dialog buttons do not have Bootstrap classes applied to them. Font Awesome icons should be used to give an indication of the kind of action being performed:
<button type="submit" class="btn btn-default approve">
<i class="fa fa-fw fa-check"></i> Yes, delete
</button>
<button type="submit" class="btn btn-default deny">
<i class="fa fa-times"></i> No, do not delete
</button>
Submit buttons
The least "specialized" button in the staff client interface is the generic submit button. This is commonly found at the end of data entry forms, for example in the form for adding a library in Administration -> Libraries and Groups:
<input type="submit" class="btn btn-primary" value="Submit" />
Action buttons in tables
When displaying tabular data, there are often actions associated with each line of data: Edit and delete for instance. As of this writing we are in the process of applying a consistent style to these actions using the Bootstrap button "btn-xs" class:
<td class="actions">
<a class="btn btn-default btn-xs" href="#"><i class="fa fa-pencil"></i> Edit</a>
<a class="btn btn-default btn-xs" href="#"><i class="fa fa-trash"></i> Delete</a>
</td>
Modals
Sometimes is useful to display some information in modal dialog, for example short forms or record previews.
We are using modals from Bootstrap 5, see full documentation here.
Basic HTML markup for modals, please note we are class closebtn for close button:
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#exampleModal">
Launch demo modal
</button>
<!-- Modal -->
<div class="modal" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title" id="exampleModalLabel">Modal title</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
...
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
Printable Modals
A modal can be made printable by adding the `printable` class the modal container div and including the modal_printer.js asset.
<div class="modal printable" tabindex="-1" role="dialog" id="myModal">
. . .
</div>
. . .
<script>
[% Asset.js("js/modal_printer.js") | $raw %]
. . .
</script>
Tabs
Koha uses Bootstrap tab markup to create tabbed interfaces.
The markup for a set of tabs includes two main parts: A list of links which will form the tabs and a corresponding set of "panels" which will form the tab contents. As with breadcrumb navigation, we use a series of Template::Toolkit WRAPPER directives to construct tabbed interfaces. A simplified example:
[% WRAPPER tabs id= "tabs container id" %]
[% WRAPPER tabs_nav %]
[% WRAPPER tab_item tabname= "tab name 1" bt_active= 1 %]
<span>Tab text 1</span>
[% END %]
[% WRAPPER tab_item tabname= "tab name 2" %]
<span>Tab text 2</span>
[% END %]
[% END %]
[% WRAPPER tab_panels %]
[% WRAPPER tab_panel tabname="tab name 1" bt_active= 1 %] [% content %] [% END %]
[% WRAPPER tab_panel tabname="tab name 2" %] [% content %] [% END %]
[% END %]
[% END %]
The "bt_active" attribute on both tab link and tab panel results in that tab being the active or open tab when the page renders. Note that the text of the tab labels must be wrapped in span tags to ensure the strings can be translated. The template markup example would render this HTML:
<div id="tabs_container_id" class="toptabs">
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="active">
<a href="#tab_name_1_panel" aria-controls="tab_name_1_panel" role="tab" data-toggle="tab">
<span>Tab text 1</span>
</a>
</li>
<li role="presentation">
<a href="#tab_name_2_panel" aria-controls="tab_name_2_panel" role="tab" data-toggle="tab">
<span>Tab text 2</span>
</a>
</li>
</ul>
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="tab_name_1_panel">
Tab panel 1
</div>
<div role="tabpanel" class="tab-pane" id="tab_name_2_panel">
Tab panel 2
</div>
</div>
</div>
Keyboard shortcuts
The staff client includes a JavaScript library for defining keyboard shortcuts. Find it here: koha-tmpl/intranet-tmpl/lib/shortcut/shortcut.js
. It is used for a few primary action shortcuts: Check in (Alt-r), Check out (Alt-u), Search (Alt-q) and Renew (Alt-w). These shortcuts are defined in staff-global.js
. For example:
shortcut.add('Alt+r',function (){
location.href="/cgi-bin/koha/circ/returns.pl";
});
The plugin is also used to define keyboard shortcuts in the advanced MARC editor.
- Getting involved | Development workflow | Bug Reporting Guidelines | RFCs | Plugins | Plugin hooks
- Version Control Using Git | git bz | Commit messages | Sign off on patches | QA Test Tools | How to QA | Debugging in VIM
- Coding Guidelines | Koha Objects | Rest Api HowTo | Coding Guidelines - API | Unit Tests | Continuous Integration | Interface patterns | Database updates | Adding a syspref | Bootstrap and LESS
- Debian Packages | Building Debian Packages | Easy Package Building | Commands
- External: Dashboard | Bugzilla | Schema | perldoc | REST API | Jenkins