twitter-bootstrapbootstrap-4

How to properly design a row in bootstrap


I am working on the front end of a library management system. As shown below, the home page has a table of books with pagination.

enter image description here

On the other side, there is a search box. The row is being split into two columns col-8 and col-4.

The following is the HTML code in Bootstrap 4.

<div class="row">
  <div class="col-8">
<div class="table-responsive-sm">
<table class="table">
  <thead>
    <tr>
      <td>Title</td>
      <td>Author</td>
      <td>Price</td>
      <td>Read</td>
    </tr>
  </thead>

  <tbody>

{% for book in books %}
  <tr>
    <td>
     {{book.title}}
    </td>
     <td>
       {% for author in book.authors.all %}
          {{author.name}} {{author.lastname}},
       {% endfor %}
     </td>
    <td>
        {{book.price}}
    </td>
    <td>
      {{book.is_read}}
    </td>
    <td>
      <a href="{% url 'book_detail' book.pk %}">View</a>
    </td>
  </tr>
    {% endfor %}

  </tbody>
</table>

  <div class="pagination justify-content-left">
      <span>
    {% if page_obj.has_previous %}
      <a href="?page={{ page_obj.previous_page_number }}">Previous</a>
    {% endif %}
    <span>
      Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
    </span>
    {% if page_obj.has_next %}
      <a href="?page={{ page_obj.next_page_number }}">Next</a>
    {% endif %}
  </span>
  </div>
</div>
  </div>

  <div class="col-4">
     This is the other part of the row,
    a col-4 column. This a project for a library
    to manage my books and analyze them. Keep track
    of my readings.

    <form method="get"> {% csrf_token %}
     <p>{{ form | crispy }}</p>
     <button type="submit">Search</button>
    </form>
  </div>
</div>

How do I align the table to have some left margin? How do I align both the table and the search box so they have an equal top margin?

And what about the Pagination code, is it placed correctly?

Another problem is that when there are less than 10 books in the table the height of the table shrinks. How can I fix that?

enter image description here


Solution

  • First of all I gave an id to:

    Then I also stripped off any templating placeholder {{ }} to focus just on the html/css and I arbitrarily filled the table with bogus data.

    Now trying to answer to your questions:

    How do I align the table to have some space on its left border?

    I set a css rule for the #section container to set its padding as padding: 2em 1em;


    How do I align both the table and the search box so they are equally distanced from the top border?

    The content of both those columns already starts at the beginning of their corresponding container. But the results table header was having some padding while the content of the search pane didn't. I changed what appeared in your code as {{ form | crispy }} with an <input type="text"> and its corresponding label both styled using bootstrap form classes AND also added a css rule setting padding: .75em; on the Title label inside #search. It was enough for the search block to have the same padding as the table header so that they share the same (~) baseline and looks vertically on the same row. Additionally I decided to add border-top on that label to have visual consistency with the border of the table on the left pane.


    What about the Pagination code, is it placed correctly?

    It's arbitrary.. for sure it looks correct to have it right below the results. On the other hand I wouldn't agree with having a right page for the search box but that's not up to me.


    Another problem is that when there are less than 10 books in the table the height of the table shrinks. How can I fix that?

    The table's height corresponds to its content. When you say it shrinks it's not clear what's your concern. Maybe it's related to how it looks compared to the search pane? You clearly asked to have the search box at the top of its container so I still don't get what do you actually mean here.


    how to place both the columns at the same height from the top border, not just the search box?

    This point was already addressed before.


    Do you have any suggestion about making the table the same height even if it has less elements than previous pages?

    What can be done, is setting a minimum height for the table so that it won't shrink further than this even if it contains a few amount of rows. But it's important you understand a caveat! when the rows are populated, their content may wrap on more lines making a single row height grow. That means a minimum fixed height MIGHT not match with the height the table would have if all its rows were populated with content word wrapping.

    Said that, you can achieve the aforementioned result by having a css rule over .table-responsive being the block level container of the table which height can be explicitely controlled. I initially attempted to set the height of the table itself but I was messing up with the table layout. So I just moved the paginator outside its container so that its size was affecting only the nested table.

    I used min-height as an arbitrary value that I chose to be 4em multiplied by 10. You can play with that value on your own to better fit your specific scenario:

    #results .table-responsive{
      min-height: calc(4em * 10);  
    }
    

    And regarding the .label-title I have a problem because I get the form from Django and just use it in the template

    I'm not sure what you are talking about.. maybe you are saying only now you can't use css rules? if that's the case just move those stylings inside a style attribute of the intended elements


    And finally:

    to have a better layout I also used table-responsive instead of table-responsive-sm because otherwise the table overflowed its container overlapping the second column when the resolution didn't hit the sm threshold.

    I also changed all the <td> elements inside the <thead> as <th> so that they get styled by bootstrap in bold meaning that's the header visually different from the table rows. In those regards I took the chance to add a cell missing in the header and causing the border to end before the rows border (those had an additional cell for the view link).

    Something more?

    Yes maybe there are a some small further additions that could be made:

    body{
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    
    #section{ 
      border: dashed 5px #ccc;  
      
      margin: 0;
      padding: 2em 1em;  
      margin: 1em;
    }
    
    #results{  
    }
    
    #results .table-responsive{
      min-height: calc(4em * 10);  
    }
    
    #search{
      padding-left: 2em;
    }
    
    .label-title{
      width: 100%;
      border-top: solid 1px #ccc;
      padding: .75em;
    }
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/4.5.3/css/bootstrap.min.css" />
    
    <div id="section" class="row">
      
      <div id="results" class="col-8 align-items-stretch">
        <div class="table-responsive">
          <table class="table">   
            <thead>
              <tr>
                <th>Title</th>
                <th>Author</th>
                <th>Price</th>
                <th>Read</th>
                <th></th>
              </tr>
            </thead>
            <tbody>          
              <tr>
                <td>title1</td>
                <td>name1 lastname1</td>
                <td>price1</td>
                <td>true</td>
                <td><a href="">View</a></td>
              </tr>          
              <tr>
                <td>title1</td>
                <td>name1 lastname1</td>
                <td>price1</td>
                <td>true</td>
                <td><a href="">View</a></td>
              </tr>          
              <tr>
                <td>title1</td>
                <td>name1 lastname1</td>
                <td>price1</td>
                <td>true</td>
                <td><a href="">View</a></td>
              </tr>          
              <!--
              <tr>
                <td>title1</td>
                <td>name1 lastname1</td>
                <td>price1</td>
                <td>true</td>
                <td><a href="">View</a></td>
              </tr>
              <tr>
                <td>title1</td>
                <td>name1 lastname1</td>
                <td>price1</td>
                <td>true</td>
                <td><a href="">View</a></td>
              </tr>          
              <tr>
                <td>title1</td>
                <td>name1 lastname1</td>
                <td>price1</td>
                <td>true</td>
                <td><a href="">View</a></td>
              </tr>          
              <tr>
                <td>title1</td>
                <td>name1 lastname1</td>
                <td>price1</td>
                <td>true</td>
                <td><a href="">View</a></td>
              </tr>          
              <tr>
                <td>title1</td>
                <td>name1 lastname1</td>
                <td>price1</td>
                <td>true</td>
                <td><a href="">View</a></td>
              </tr>          
              -->
            </tbody>
          </table>            
        </div>
        
        <div class="pagination justify-content-left">
          <span>          
            <a href="">Previous</a>          
            <span>Page 1 of 1.</span>          
            <a href="">Next</a>          
          </span>
        </div>
        
      </div>
    
      <div id="search" class="col-4">    
        <form method="get">
          <div class="mb-3">
            <label class="form-label label-title">Title</label>
            <input type="text" class="form-control">
          </div>
          <button type="submit" class="btn btn-primary">Search</button>
        </form>
      </div>
    </div>