How to make a pricing table
Short answer
Plans are cards in a responsive grid. The recommended one is highlighted with a border:
<style>
.plans { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 10px; }
.plan { display: flex; flex-direction: column; padding: 14px; border: 1px solid gainsboro; border-radius: 12px; }
.plan.best { border: 2px solid royalblue; box-shadow: 0 4px 14px rgb(65 105 225 / 25%); }
.plan b { font-size: 26px; }
.plan ul { padding-left: 18px; font-size: 14px; }
.plan button { margin-top: auto; padding: 8px; }
</style>
<div class="plans">
<div class="plan"><h3>Basic</h3><b>$0</b><ul><li>1 project</li></ul><button>Start</button></div>
<div class="plan best"><h3>Pro</h3><b>$12</b><ul><li>10 projects</li><li>Priority support</li></ul><button>Choose Pro</button></div>
<div class="plan"><h3>Team</h3><b>$29</b><ul><li>Unlimited projects</li><li>5 members</li></ul><button>Contact us</button></div>
</div>Buttons on the same level
Plans have different numbers of features, and without care the buttons end up at different heights. Each card is a flexbox column, and margin-top: auto on the button pushes it to the bottom. Grid evens out the heights of cards in one row by itself.
A "Popular" label
A label is often placed above the highlighted card. Give the card position: relative and the label position: absolute; top: -10px — more in the answer on placing an element in a corner.
Common mistake
Building the plans as a real table. On a phone three columns do not fit, and the table overflows the screen. Grid cards stack by themselves. A table only makes sense for a detailed feature comparison below the cards.
Functions used in this recipe
- grid-template-columns — The number and widths of the columns of a grid.
- repeat() — Repeats grid tracks instead of writing them out one by one.
- <ul> — A bulleted list: items whose order does not matter.
- box-shadow — A shadow around the element's box.