If you're a Web developer, you know you should target your Web applications to be “mobile first.” This means that your Web applications should look great on a mobile device, and good, if not great, on a desktop browser. There are many techniques you can use to help you develop for mobile. One technique is to use Bootstrap to give yourself responsive styles that change based on the device being used. Another technique, and the focus of this article, is to eliminate HTML tables.
HTML tables, when not used correctly, can cause problems with small screens such as those found on smart phones. This article shows you how to rework your HTML tables to fit better on mobile devices. In addition, you'll learn to use Bootstrap panel
classes to completely eliminate HTML tables.
The Problem with HTML Tables
HTML tables are used by many Web developers because they're easy to program, and provide a way for users to see a lot of information like they would on a spreadsheet. But just because something is easy to use and conveys a lot of data, doesn't necessarily mean it's the best tool. There are many reasons why an HTML table isn't suitable for user consumption.
- A table presents too much data on the page, so the user has too much to concentrate upon.
- A user's eyes become fatigued after staring at rows and columns of data much more quickly than when data is spread out.
- It's hard for a user to distinguish between the data in each column because each column is uniform and nothing stands out.
- On a mobile device, the user frequently needs to pan right and left to see all the data. This leads to an annoyed user, and is very unproductive.
HTML Table on Desktop versus Mobile
In Figure 1, you see a list of tabular product data. This renders nicely on a normal desktop browser because the user has a lot of screen real-estate and they don't need to scroll left and right to see all the data.
Look at this same page rendered on a smart phone, as shown in Figure 2. The user is only able to see the left-most column of the table. If they don't know that they can scroll to the right, they're missing some important information. On some mobile browsers, the page may render the complete table, but it's so small that it's hard to read. Either way, the user is forced to interact with their phone to view the data. They must scroll left to right, or maybe pinch or spread with their fingers.
Create an MVC Project
If you wish to follow along creating the sample for this article, create a new MVC project using Visual Studio. Name the project AlternativeTable
. Once you have a new MVC project, add three classes into the \Models folder
. The names for each of these classes are Product
, ProductManager
, and ProductViewModel
. Instead of using a database, create some mock data in the ProductManager
class. The Product
class is shown in the following code snippet:
public class Product
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public DateTime IntroductionDate { get; set; }
public string Url { get; set; }
public decimal Price { get; set; }
}
Several lines of the ProductManager
class are shown in Listing 1. You need to add a few more Product
objects into the list so you can display several rows of data. Or, see the sidebar for how to download the complete sample. You can then copy the ProductManager.cs
class into the \Models folder
to have several product
objects to display while running this sample.
Listing 1: Create some mock data in the ProductManager class
public class ProductManager
{
public List<Product> Get() {
return CreateMockData();
}
protected List<Product> CreateMockData() {
List<Product> ret = new List<Product>();
ret.Add(new Product()
{
ProductId = 1,
ProductName = "Add Angular to MVC Applications",
IntroductionDate = Convert.ToDateTime("07/25/2017"),
Url = "http://bit.ly/2u1ofRk",
Price = Convert.ToDecimal(29.00)
});
// MORE PRODUCTS CREATED HERE
return ret;
}
}
The last
class is a view model that's called from the MVC Controller. Using an MVVM approach to development provides for a nice separation of concerns in your applications. It's also very easy to bind properties in your CSHTML pages to your view model classes. The ProductViewModel
class is shown in the following code snippet.
public class ProductViewModel
{
public List<Product> Products { get; set; } = new List<Product>();
public void LoadProducts() {ProductManager mgr = new ProductManager();
Products = mgr.Get();
}
}
The MVC Controller
You need a MVC controller to load the data and feed that data to the CSHTML pages used to render your page of product data. Right mouse-click on the Controllers folder, select Add > Controller… Select MVC 5 Controller ? Empty from the list of templates and click the Add button. Change the name to ProductController
and click the OK button. Write the following code in the Index
method.
public ActionResult Index()
{
ProductViewModel vm = new ProductViewModel();
vm.LoadProducts();
return View(vm);
}
This method creates an instance of the ProductViewModel
class and calls the LoadProducts
method to build the Products
property in the view model. The CSHTML page you are going to build uses the Products
property of the View Model passed to it to build the HTML table.
The HTML Table View
Create a new folder under the \Views folder
called \Product
. Right mouse-click on this folder name and select Add > MVC 5 View Page with Layout (Razor) from the menu. Set the name to Index
and click the OK button. When presented with a list of layouts, choose _Layout.cshtml
from the dialog box and click the OK button. Write the code shown in Listing 2.
Listing 2: Create a normal HTML table as a starting point
@model AlternativeTable.ProductViewModel
@{
ViewBag.Title = "Products";
}
<h2>Products</h2>
<div class="table-responsive">
<table class="table table-bordered table-condensed table-striped">
<thead>
<tr>
<th>Product Name</th>
<th>Introduction Date</th>
<th class="text-right">Price</th>
<th>URL</th>
<th class="text-center">Delete</th>
</tr>
</thead>
<tbody>
@foreach (Product item in Model.Products) {
<tr>
<td> <a href="#" title="Edit Product">@item.ProductName</a> </td>
<td> @item.IntroductionDate.ToShortDateString() </td>
<td class="text-right">@item.Price.ToString("c")</td>
<td>@item.Url</td>
<td class="text-center"><a href="#"
title="Delete Product"
class="btn btn-sm btn-default">
<i class="glyphicon glyphicon-trash"> </i>
</a>
</td>
</tr>
}
</tbody>
</table>
</div>
As you can see from Listing 2, there's nothing out of the ordinary for this table. You use Bootstrap table
classes to help with styling the table. You loop through the collection of product data in the Products
property of the ProductViewModel
class. Each time through the loop, display the appropriate data from the Product
class in each <td>
of the table. You should be able to run the application at this point and see your table of product data appear. If you wish to see what this page looks like on a smart phone, you can purchase Electric Mobile Studio 2012 from Electric Plum at https://www.electricplum.com/studio.aspx.
Before you continue with this article, please copy the contents of your CSHTML page into Notepad, or save it to another file. You're going to use this Razor code later in this article.
Remove Table-Responsive Class
There's one more thing to try before you move onto the next section. Remove the attribute class=“table-responsive” from the <div>
surrounding the <table>
element. Re-run the application and look at the result. You should now see more of the table, but the data is now wrapped within the columns. This can give you a little more data showing in the table, but you're right back to having too much data in too little space. If you have several more columns, it also forces the user to scroll left and right to see all of the data.
Reduce Table to Two Columns
If you reduce your table to two columns, you find that it fits on a small device screen just fine (See Figure 3 and Figure 4). Make the changes to the page you just created by first modifying the columns in the <thead>
area, as shown in the following code snippet:
<thead>
<tr>
<th>Product Information</th>
<th class="text-center">Delete</th>
</tr>
</thead>
You don't want to remove any of the data from your product HTML table; you just want to redistribute it into two columns. Leave the delete button in the last column, but take the code that displays the Introduction Date, Price, and URL columns and put them into the first column, as shown in the following code snippet:
<td>
<p>
<a href="#" title="Edit Product">@item.ProductName</a>
</p>
<strong>Intro. Date: </strong>@item.IntroductionDate.ToShortDateString()<br />
<strong>Price: </strong>@item.Price.ToString("c")<br />
<strong>URL: </strong>@item.Url
</td>
You should now just have two <td>
elements remaining in the <tbody>
of your table. If you haven't already done so, remove the attribute class=“table-responsive” from the <div>
surrounding the