A ready-to-use pricing table is one of those resources to have in our toolbox. They are not particular challenging in terms of design and user experience, yet they represent a key section of our web page: it's where the potential client takes action.

We put together an easy-to-customise pricing table, in 3 different styles. Besides we integrated our popular Bouncy Content Filter as transition while switching from one plan to another.

On small devices we took a new approach: instead of listing all the features vertically - which would force the user to scroll a lot to go past the pricing section, we listed them horizontally. This way we save a lot of space; users can compare all the prices at a glance, and they can dive deeper into the features if interested.

Creating the structure

The HTML is structured in 2 blocks: a div.cd-pricing-switcher containing the filter, and a ul.cd-pricing-list , containing the pricing tables. Inside each list item of the .cd-pricing-list we nested a second ul element (the one which rotates) containing the pricing tables as list items.

Each pricing table is made up of a .cd-pricing-header (containing plan title and price), a .cd-pricing-body (containing plan features) and a .cd-pricing-footer (containing the action button).

<div class="cd-pricing-container"> <div class="cd-pricing-switcher"> <p class="fieldset"> <input type="radio" name="duration" value="monthly" id="monthly" checked> <label for="monthly">Monthly</label> <input type="radio" name="duration" value="yearly" id="yearly"> <label for="yearly">Yearly</label> <span class="cd-switch"></span> </p> </div> <!-- .cd-pricing-switcher --> <ul class="cd-pricing-list"> <li> <ul class="cd-pricing-wrapper"> <li data-type="monthly" class="is-visible"> <header class="cd-pricing-header"> <h2>Basic</h2> <div class="cd-price"> <span class="cd-currency">$</span> <span class="cd-value">30</span> <span class="cd-duration">mo</span> </div> </header> <!-- .cd-pricing-header --> <div class="cd-pricing-body"> <ul class="cd-pricing-features"> <li><em>256MB</em> Memory</li> <!-- other features here --> </ul> </div> <!-- .cd-pricing-body --> <footer class="cd-pricing-footer"> <a class="cd-select" href="http://codyhouse.co">Select</a> </footer> <!-- .cd-pricing-footer --> </li> <li data-type="yearly" class="is-hidden"> <!-- pricing table content here --> </li> </ul> <!-- .cd-pricing-wrapper --> </li> <li class="cd-popular"> <ul class="cd-pricing-wrapper"> <li data-type="monthly" class="is-visible"> <!-- pricing table content here --> </li> <li data-type="yearly" class="is-hidden"> <!-- pricing table content here --> </li> </ul> </li> <!-- .cd-pricing-wrapper --> <li> <ul class="cd-pricing-wrapper"> <li data-type="monthly" class="is-visible"> <!-- pricing table content here --> </li> <li data-type="yearly" class="is-hidden"> <!-- pricing table content here --> </li> </ul> <!-- .cd-pricing-wrapper --> </li> </ul> <!-- .cd-pricing-list --> </div> <!-- .cd-pricing-container -->

Adding style

On small devices, the .cd-pricing-footer is in position: absolute and placed over the .cd-pricing-header to cover it (we assigned the same height to both elements). The action button has a display: block and height: 100% so that it has the same dimension of the table footer (the pointer-events: none assigned to the .cd-pricing-header assures that the button is clickable).

The .cd-pricing-body has overflow-x: auto to hide part of the ul.cd-pricing-features element - whose width could be higher.

.cd-pricing-header { height: 80px; pointer-events: none; } .cd-pricing-body { overflow-x: auto; /* smooth scrolling on touch devices */ -webkit-overflow-scrolling: touch; } .cd-pricing-footer { position: absolute; top: 0; left: 0; height: 80px; width: 100%; } .cd-select { display: block; height: 100%; /* hide button text on mobile */ overflow: hidden; text-indent: 100%; white-space: nowrap; color: transparent; }

On desktop devices (viewport width more than 1170px), the css is pretty straightforward (you can find additional comments in the scss/css file for the tricky parts).

One important note : we created 3 classes to customise the pricing tables (all classes have to be applied to the .cd-pricing-container element):

cd-full-width - set width: 100% to the .cd-pricing-container , with max-width: none (as default, we set width: 90% and max-width: 1170px);

- set width: 100% to the , with max-width: none (as default, we set width: 90% and max-width: 1170px); cd-tables-have-margin - add a right margin to the pricing tables;

- add a right margin to the pricing tables; cd-secondary-theme - different color theme combination;

In our demo we created 3 different table styles: the first is the default one, the second is obtained adding to the .cd-pricing-container both .cd-full-width and .cd-second-theme classes, and the last adding the .cd-tables-have-margin class.

One important note: the styles associated to these 3 classes differ on desktop devices only.

Additional note on the bouncy animation: as pointed out in the comments, if you have only 2 switching options (in our demo 'Monthly' and 'Yearly'), it feels more natural to invert the rotation direction while switching from one option to the other. For this reason, we created the .cd-bounce-invert class to be added to the ul.cd-pricing-list . If you have more than 2 options, just remove this class and the rotation will preserve the direction.

Events handling

For the pricing table rotation, you can check what we did for the Bouncy Content Filter.

Besides, we used jQuery to remove the subtle gradient on the right side of the pricing table body (mobile version only) – that we added to indicate that there’s more content – at the end of the scrolling.