Pricing

Three plans whose icons play when the pointer enters the card. In four layouts.

Take it with you

This demo also exists as a standalone project — npm install && npm run dev, no changes needed.

npx giget@latest gh:lordicondev/ui-components/pricing#standalone pricing

Copies the pricing folder of the standalone branch — where every demo lives on its own — into ./pricing.

How it works

Define the element, put the icon in the markup, set the control's state. Then the parts that make this demo different.

Define the element Built-in triggers only. Apart from the dots, this is the whole script.
import { defineElement } from '@lordicon/element';

// Registers <lord-icon> with its built-in triggers. The markup says what each icon does.
defineElement();
A plan card target points the icon at the card, so the whole card is the hover area. The ticks are plain SVG.
html
<!-- target makes the whole card the hover area for the plan's icon. The ticks are
     plain SVG. -->
<article class="plan">
    <div class="plan__head">
        <span class="plan__well">
            <lord-icon
                class="plan__icon"
                current-color
                src="icons/puzzle-piece.json"
                loading="interaction"
                trigger="hover"
                target=".plan"
                aria-hidden="true"
            >
                <img alt="" src="icons/puzzle-piece.svg" />
            </lord-icon>
        </span>
        <h2 class="plan__name">Starter</h2>
        <p class="plan__price">$10/month</p>
    </div>

    <!-- … -->

    <button class="plan__action" type="button">Try for free</button>
</article>
Grey icons and accent ones The icons inherit color through current-color. The black SVGs take a filter.
css
/* Grey icons, and accent ones on the featured card. A plan's icon takes color; its
   placeholder and the SVG ticks, which are black, take the same colour as a filter. */
.plan__icon {
    color: var(--ink-soft);
    --icon-filter: var(--filter-ink-soft);
}

.feature__tick {
    --icon-filter: var(--filter-ink-subtle);
}

.plan--featured .plan__icon {
    color: var(--accent);
    --icon-filter: var(--filter-accent);
}

.plan--featured .feature__tick {
    --icon-filter: var(--filter-accent-strong);
}
The icon on the top border Positioned on the card and pulled up by half its height, so it sits on the line.
css
/* The icon sits on the top border, centred, over a centred name and price. */
.plans--raised .plan {
    padding-top: var(--space-48);
    box-shadow: none;
}

.plans--raised .plan__head {
    align-items: center;
}

.plans--raised .plan__name {
    font-size: var(--text-lg);
}

.plans--raised .plan__well {
    position: absolute;
    top: 0;
    left: 50%;
    translate: -50% calc(-50% - 1px);
    border-radius: var(--radius-md);
}
Name and price in one row No icon in the markup. The rule is the head's bottom border.
css
/* No icon. Name and price share a row, with a rule under them. */
.plans--compact .plan__head {
    flex-direction: row;
    justify-content: space-between;
    padding-bottom: var(--space-24);
    border-bottom: 1px solid var(--border);
    /* 24px from the rule to the features, not the card's 32. */
    margin-bottom: calc(var(--space-24) - var(--space-32));
}

.plans--compact .plan__name {
    font-size: var(--text-lg);
}

.plans--compact .features {
    gap: var(--space-12);
}

.plans--compact .feature__tick {
    width: var(--icon-size-20);
    height: var(--icon-size-20);
}

Every file

The demo's own files, whole, at the paths the export uses.

index.html 782 lines
html
<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <title>Pricing</title>
        <link rel="stylesheet" href="./pricing.css" />
        <script type="module" src="./main.ts"></script>
    </head>

    <body>
        <main class="demo">
            <section class="plans" id="layout-icons" data-page aria-label="Plans">
                <!-- target makes the whole card the hover area for the plan's icon. The ticks are
                     plain SVG. -->
                <article class="plan">
                    <div class="plan__head">
                        <span class="plan__well">
                            <lord-icon
                                class="plan__icon"
                                current-color
                                src="icons/puzzle-piece.json"
                                loading="interaction"
                                trigger="hover"
                                target=".plan"
                                aria-hidden="true"
                            >
                                <img alt="" src="icons/puzzle-piece.svg" />
                            </lord-icon>
                        </span>
                        <h2 class="plan__name">Starter</h2>
                        <p class="plan__price">$10/month</p>
                    </div>

                    <div class="plan__features">
                        <h3 class="plan__lead">Key features:</h3>
                        <ul class="features">
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                100 GB storage
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                Sync across 2 devices
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                7-day version history
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                Email support
                            </li>
                        </ul>
                    </div>

                    <button class="plan__action" type="button">Try for free</button>
                </article>

                <article class="plan plan--featured">
                    <div class="plan__head">
                        <span class="plan__well">
                            <lord-icon
                                class="plan__icon"
                                current-color
                                src="icons/rocket.json"
                                loading="interaction"
                                trigger="hover"
                                target=".plan"
                                aria-hidden="true"
                            >
                                <img alt="" src="icons/rocket.svg" />
                            </lord-icon>
                        </span>
                        <h2 class="plan__name">Plus</h2>
                        <p class="plan__price">$12/month</p>
                    </div>

                    <div class="plan__features">
                        <h3 class="plan__lead">Key features:</h3>
                        <ul class="features">
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                2 TB storage
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                Unlimited devices
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                30-day version history
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                Advanced sharing controls
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                Priority support
                            </li>
                        </ul>
                    </div>

                    <button class="plan__action" type="button">Get started</button>
                </article>

                <article class="plan">
                    <div class="plan__head">
                        <span class="plan__well">
                            <lord-icon
                                class="plan__icon"
                                current-color
                                src="icons/avatars-group.json"
                                loading="interaction"
                                trigger="hover"
                                target=".plan"
                                aria-hidden="true"
                            >
                                <img alt="" src="icons/avatars-group.svg" />
                            </lord-icon>
                        </span>
                        <h2 class="plan__name">Business</h2>
                        <p class="plan__price">$24/month</p>
                    </div>

                    <div class="plan__features">
                        <h3 class="plan__lead">Key features:</h3>
                        <ul class="features">
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                5 TB storage per user
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                Admin console
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                SSO &amp; audit logs
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                Dedicated account manager
                            </li>
                        </ul>
                    </div>

                    <button class="plan__action" type="button">Contact sales</button>
                </article>
            </section>

            <section class="plans" id="layout-badge" data-page hidden aria-label="Plans">
                <article class="plan">
                    <div class="plan__head">
                        <span class="plan__well">
                            <lord-icon
                                class="plan__icon"
                                current-color
                                src="icons/puzzle-piece.json"
                                loading="interaction"
                                trigger="hover"
                                target=".plan"
                                aria-hidden="true"
                            >
                                <img alt="" src="icons/puzzle-piece.svg" />
                            </lord-icon>
                        </span>
                        <h2 class="plan__name">Starter</h2>
                        <p class="plan__price">$10/month</p>
                    </div>

                    <div class="plan__features">
                        <h3 class="plan__lead">Key features:</h3>
                        <ul class="features">
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                100 GB storage
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                Sync across 2 devices
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                7-day version history
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                Email support
                            </li>
                        </ul>
                    </div>

                    <button class="plan__action" type="button">Try for free</button>
                </article>

                <article class="plan plan--featured">
                    <p class="plan__badge">Bestseller</p>

                    <div class="plan__head">
                        <span class="plan__well">
                            <lord-icon
                                class="plan__icon"
                                current-color
                                src="icons/rocket.json"
                                loading="interaction"
                                trigger="hover"
                                target=".plan"
                                aria-hidden="true"
                            >
                                <img alt="" src="icons/rocket.svg" />
                            </lord-icon>
                        </span>
                        <h2 class="plan__name">Plus</h2>
                        <p class="plan__price">$12/month</p>
                    </div>

                    <div class="plan__features">
                        <h3 class="plan__lead">Key features:</h3>
                        <ul class="features">
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                2 TB storage
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                Unlimited devices
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                30-day version history
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                Advanced sharing controls
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                Priority support
                            </li>
                        </ul>
                    </div>

                    <button class="plan__action" type="button">Get started</button>
                </article>

                <article class="plan">
                    <div class="plan__head">
                        <span class="plan__well">
                            <lord-icon
                                class="plan__icon"
                                current-color
                                src="icons/avatars-group.json"
                                loading="interaction"
                                trigger="hover"
                                target=".plan"
                                aria-hidden="true"
                            >
                                <img alt="" src="icons/avatars-group.svg" />
                            </lord-icon>
                        </span>
                        <h2 class="plan__name">Business</h2>
                        <p class="plan__price">$24/month</p>
                    </div>

                    <div class="plan__features">
                        <h3 class="plan__lead">Key features:</h3>
                        <ul class="features">
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                5 TB storage per user
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                Admin console
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                SSO &amp; audit logs
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                Dedicated account manager
                            </li>
                        </ul>
                    </div>

                    <button class="plan__action" type="button">Contact sales</button>
                </article>
            </section>

            <section
                class="plans plans--raised"
                id="layout-raised"
                data-page
                hidden
                aria-label="Plans"
            >
                <article class="plan">
                    <div class="plan__head">
                        <span class="plan__well">
                            <lord-icon
                                class="plan__icon"
                                current-color
                                src="icons/puzzle-piece.json"
                                loading="interaction"
                                trigger="hover"
                                target=".plan"
                                aria-hidden="true"
                            >
                                <img alt="" src="icons/puzzle-piece.svg" />
                            </lord-icon>
                        </span>
                        <h2 class="plan__name">Starter</h2>
                        <p class="plan__price">$10/month</p>
                    </div>

                    <div class="plan__features">
                        <h3 class="plan__lead">Key features:</h3>
                        <ul class="features">
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                100 GB storage
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                Sync across 2 devices
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                7-day version history
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                Email support
                            </li>
                        </ul>
                    </div>

                    <button class="plan__action" type="button">Try for free</button>
                </article>

                <article class="plan plan--featured">
                    <div class="plan__head">
                        <span class="plan__well">
                            <lord-icon
                                class="plan__icon"
                                current-color
                                src="icons/rocket.json"
                                loading="interaction"
                                trigger="hover"
                                target=".plan"
                                aria-hidden="true"
                            >
                                <img alt="" src="icons/rocket.svg" />
                            </lord-icon>
                        </span>
                        <h2 class="plan__name">Plus</h2>
                        <p class="plan__price">$12/month</p>
                    </div>

                    <div class="plan__features">
                        <h3 class="plan__lead">Key features:</h3>
                        <ul class="features">
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                2 TB storage
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                Unlimited devices
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                30-day version history
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                Advanced sharing controls
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                Priority support
                            </li>
                        </ul>
                    </div>

                    <button class="plan__action" type="button">Get started</button>
                </article>

                <article class="plan">
                    <div class="plan__head">
                        <span class="plan__well">
                            <lord-icon
                                class="plan__icon"
                                current-color
                                src="icons/avatars-group.json"
                                loading="interaction"
                                trigger="hover"
                                target=".plan"
                                aria-hidden="true"
                            >
                                <img alt="" src="icons/avatars-group.svg" />
                            </lord-icon>
                        </span>
                        <h2 class="plan__name">Business</h2>
                        <p class="plan__price">$24/month</p>
                    </div>

                    <div class="plan__features">
                        <h3 class="plan__lead">Key features:</h3>
                        <ul class="features">
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                5 TB storage per user
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                Admin console
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                SSO &amp; audit logs
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                Dedicated account manager
                            </li>
                        </ul>
                    </div>

                    <button class="plan__action" type="button">Contact sales</button>
                </article>
            </section>

            <section
                class="plans plans--compact"
                id="layout-compact"
                data-page
                hidden
                aria-label="Plans"
            >
                <article class="plan">
                    <div class="plan__head">
                        <h2 class="plan__name">Starter</h2>
                        <p class="plan__price">$10/month</p>
                    </div>

                    <div class="plan__features">
                        <h3 class="plan__lead">Key features:</h3>
                        <ul class="features">
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                100 GB storage
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                Sync across 2 devices
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                7-day version history
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                Email support
                            </li>
                        </ul>
                    </div>

                    <button class="plan__action" type="button">Try for free</button>
                </article>

                <article class="plan plan--featured">
                    <div class="plan__head">
                        <h2 class="plan__name">Plus</h2>
                        <p class="plan__price">$12/month</p>
                    </div>

                    <div class="plan__features">
                        <h3 class="plan__lead">Key features:</h3>
                        <ul class="features">
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                2 TB storage
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                Unlimited devices
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                30-day version history
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                Advanced sharing controls
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                Priority support
                            </li>
                        </ul>
                    </div>

                    <button class="plan__action" type="button">Get started</button>
                </article>

                <article class="plan">
                    <div class="plan__head">
                        <h2 class="plan__name">Business</h2>
                        <p class="plan__price">$24/month</p>
                    </div>

                    <div class="plan__features">
                        <h3 class="plan__lead">Key features:</h3>
                        <ul class="features">
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                5 TB storage per user
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                Admin console
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                SSO &amp; audit logs
                            </li>
                            <li class="feature">
                                <img
                                    class="feature__tick"
                                    alt=""
                                    src="icons/check-circle-solid.svg"
                                />
                                Dedicated account manager
                            </li>
                        </ul>
                    </div>

                    <button class="plan__action" type="button">Contact sales</button>
                </article>
            </section>

            <div class="pager">
                <button
                    class="pager__dot"
                    type="button"
                    aria-pressed="true"
                    aria-controls="layout-icons"
                    aria-label="Icon above the name"
                ></button>
                <button
                    class="pager__dot"
                    type="button"
                    aria-pressed="false"
                    aria-controls="layout-badge"
                    aria-label="With a badge"
                ></button>
                <button
                    class="pager__dot"
                    type="button"
                    aria-pressed="false"
                    aria-controls="layout-raised"
                    aria-label="Icon on the edge"
                ></button>
                <button
                    class="pager__dot"
                    type="button"
                    aria-pressed="false"
                    aria-controls="layout-compact"
                    aria-label="Name and price in one row"
                ></button>
            </div>
        </main>
    </body>
</html>
main.ts 9 lines
import { defineElement } from '@lordicon/element';

// Registers <lord-icon> with its built-in triggers. The markup says what each icon does.
defineElement();

import { pager } from '@shared/ui/pager.ts';

// Four layouts of the same three cards, behind the dots.
pager();
pricing.css 215 lines
css
@import '@shared/styles/index.css';
@import '@shared/ui/pager.css';

/* The cards above, the dots below. */
.demo {
    display: grid;
    grid-template-rows: 1fr auto;
    justify-items: center;
    align-items: center;
    gap: var(--space-48);
    min-height: 100dvh;
    padding: var(--space-64) var(--gutter) var(--space-32);
}

/* Three columns from 920px, the narrowest at which no line wraps; one below that. The
   middle column is a little wider. Cards in a row stretch to the tallest, so the buttons
   line up. The row gap leaves room for the badge and the raised icon. */
.plans {
    display: grid;
    grid-template-columns: minmax(0, 360px);
    justify-content: center;
    gap: var(--space-48) var(--space-16);
    width: 100%;
}

@media (min-width: 920px) {
    .plans {
        grid-template-columns: 1fr 1.12fr 1fr;
        max-width: 1160px;
    }
}

.plan {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: var(--space-32);
    padding: var(--space-24) var(--space-24) var(--space-16);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--surface);
    box-shadow: 0 1px 1.5px rgb(0 0 0 / 4%);
}

.plan__head {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-12);
}

.plan__well {
    display: flex;
    padding: var(--space-12);
    border-radius: var(--radius-pill);
    background: var(--surface-muted);
}

.plan__name,
.plan__price,
.plan__lead {
    margin: 0;
    font-size: var(--text-base);
    font-weight: 600;
}

.plan__price {
    font-size: var(--text-xl);
}

.plan__features {
    display: flex;
    flex-direction: column;
    gap: var(--space-12);
}

.features {
    display: flex;
    flex-direction: column;
    gap: var(--space-8);
    margin: 0;
    padding: 0;
    list-style: none;
}

.feature {
    display: flex;
    align-items: center;
    gap: var(--space-8);
    color: var(--ink-soft);
    font-size: var(--text-sm);
}

.feature__tick {
    flex: none;
    width: var(--icon-size-16);
    height: var(--icon-size-16);
    filter: var(--icon-filter);
}

/* Pushed to the bottom of a card that is taller than its content. */
.plan__action {
    margin-top: auto;
    padding: 7px var(--space-12);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface);
    font-weight: 500;
    cursor: pointer;
}

.plan__action:hover {
    background: var(--surface-muted);
}

.plan--featured {
    border-color: var(--border-accent);
}

.plan--featured .plan__well {
    background: var(--accent-surface);
}

.plan--featured .plan__action {
    border-color: var(--accent);
    background: var(--accent);
    color: var(--ink-inverse);
    box-shadow: var(--shadow-accent);
}

.plan--featured .plan__action:hover {
    border-color: var(--accent-strong);
    background: var(--accent-strong);
}

/* 12px above the card's border. */
.plan__badge {
    position: absolute;
    top: -13px;
    left: 50%;
    translate: -50% 0;
    margin: 0;
    padding: var(--space-8) var(--space-12);
    border-radius: var(--radius-sm);
    background: var(--accent);
    color: var(--ink-inverse);
    font-size: var(--text-sm);
    font-weight: 500;
    line-height: var(--leading-xs);
}

/* Grey icons, and accent ones on the featured card. A plan's icon takes color; its
   placeholder and the SVG ticks, which are black, take the same colour as a filter. */
.plan__icon {
    color: var(--ink-soft);
    --icon-filter: var(--filter-ink-soft);
}

.feature__tick {
    --icon-filter: var(--filter-ink-subtle);
}

.plan--featured .plan__icon {
    color: var(--accent);
    --icon-filter: var(--filter-accent);
}

.plan--featured .feature__tick {
    --icon-filter: var(--filter-accent-strong);
}

/* The icon sits on the top border, centred, over a centred name and price. */
.plans--raised .plan {
    padding-top: var(--space-48);
    box-shadow: none;
}

.plans--raised .plan__head {
    align-items: center;
}

.plans--raised .plan__name {
    font-size: var(--text-lg);
}

.plans--raised .plan__well {
    position: absolute;
    top: 0;
    left: 50%;
    translate: -50% calc(-50% - 1px);
    border-radius: var(--radius-md);
}

/* No icon. Name and price share a row, with a rule under them. */
.plans--compact .plan__head {
    flex-direction: row;
    justify-content: space-between;
    padding-bottom: var(--space-24);
    border-bottom: 1px solid var(--border);
    /* 24px from the rule to the features, not the card's 32. */
    margin-bottom: calc(var(--space-24) - var(--space-32));
}

.plans--compact .plan__name {
    font-size: var(--text-lg);
}

.plans--compact .features {
    gap: var(--space-12);
}

.plans--compact .feature__tick {
    width: var(--icon-size-20);
    height: var(--icon-size-20);
}
What it imports 6 shared files
shared/styles/base.css 115 lines
css
/*
 * Fonts, reset and default typography. Nothing control-specific: every demo styles its
 * own control. Only the UI face is here; the mono face is the portal's.
 */
@font-face {
    font-family: 'Figtree';
    font-style: normal;
    font-weight: 300 900;
    font-display: swap;
    src: url('../fonts/figtree-latin.woff2') format('woff2');
    unicode-range:
        U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308,
        U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'Figtree';
    font-style: normal;
    font-weight: 300 900;
    font-display: swap;
    src: url('../fonts/figtree-latin-ext.woff2') format('woff2');
    unicode-range:
        U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329,
        U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113,
        U+2C60-2C7F, U+A720-A7FF;
}

/* Arial with Figtree's measurements, for the moment before Figtree arrives, so the text does
   not move when it does. Measured on Figtree at 400 and 500. */
@font-face {
    font-family: 'Figtree fallback';
    src: local('Arial'), local('Liberation Sans');
    size-adjust: 100.3%;
    ascent-override: 94.7%;
    descent-override: 24.9%;
    line-gap-override: 0%;
}

*,
*::before,
*::after {
    box-sizing: border-box;
}

/* An author `display` on a component would beat the UA rule for [hidden], and then
   `el.hidden = true` would stop working. Settled once here. */
[hidden] {
    display: none !important;
}

body {
    margin: 0;
    background: var(--surface);
    color: var(--ink);
    --icon-filter: var(--filter-ink);
    font-family: var(--font-ui);
    font-size: var(--text-base);
    line-height: var(--leading-base);
    -webkit-font-smoothing: antialiased;
}

button,
input,
textarea,
select {
    font: inherit;
    color: inherit;
}

/* A second click on a button would otherwise select its label. */
button {
    -webkit-user-select: none;
    user-select: none;
}

:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/*
 * In the accessibility tree but not on screen: labels and legends that the visual design
 * has no room for. Clipped rather than `display: none`, which would remove it from the
 * tree too, and it also hides live radio inputs that must stay reachable by keyboard.
 */
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/*
 * Until the script defines <lord-icon> it is an unknown inline element with no size. These
 * rules give it the box it will have, so nothing moves when it is defined.
 */
lord-icon {
    display: inline-block;
    width: var(--icon-size-32);
    height: var(--icon-size-32);
}

/* A placeholder inside the icon fills it until the icon is ready. */
lord-icon:not(:defined) > img {
    display: block;
    width: 100%;
    height: 100%;
}

/* Placeholders are black. Set --icon-filter wherever an icon's colour is set. */
lord-icon > img {
    filter: var(--icon-filter);
}
shared/styles/index.css 4 lines
css
/* The one stylesheet a demo imports. */
@import './palette.css';
@import './tokens.css';
@import './base.css';
shared/styles/palette.css 87 lines
css
/*
 * Generated from the Figma token export.
 * Raw values only — roles live in tokens.css. Edit the Figma variables, not this file.
 */
:root {
    /* color/ink */
    --gray-0: #FFFFFF;
    --gray-50: #F7F8FA;
    --gray-100: #EEF0F3;
    --gray-200: #DEE1E6;
    --gray-300: #C3C7D0;
    --gray-400: #9BA1AD;
    --gray-500: #767C89;
    --gray-600: #565C68;
    --gray-700: #3D414B;
    --gray-800: #282B33;
    --gray-900: #16181D;
    --gray-950: #0A0B0E;

    /* color/signal */
    --brand-100: #FFEEE9;
    --brand-200: #FFD7CA;
    --brand-300: #FFB199;
    --brand-400: #FF7D5C;
    --brand-500: #FF5A36;
    --brand-600: #E8431F;
    --brand-700: #C2340F;

    /* color/success */
    --green-100: #EDF9F1;
    --green-300: #A7D9BC;
    --green-700: #15803D;

    /* color/error */
    --red-100: #FDECEC;
    --red-300: #F5B5B5;
    --red-700: #DC2626;

    /* typography/font */
    --font-ui-name: 'Figtree';
    --font-mono-name: 'JetBrains Mono';

    /* typography/size */
    --text-xs: 12px;
    --text-sm: 14px;
    --text-base: 16px;
    --text-lg: 20px;
    --text-xl: 24px;
    --text-2xl: 32px;
    --text-3xl: 40px;

    /* typography/lineHeight */
    --leading-xs: 16px;
    --leading-sm: 20px;
    --leading-base: 24px;
    --leading-lg: 28px;
    --leading-xl: 32px;
    --leading-2xl: 40px;
    --leading-3xl: 48px;

    /* spacing (named after the value, the Figma scale is non-linear) */
    --space-4: 4px;
    --space-8: 8px;
    --space-12: 12px;
    --space-16: 16px;
    --space-24: 24px;
    --space-32: 32px;
    --space-48: 48px;
    --space-64: 64px;
    --space-96: 96px;

    /* size/icon */
    --icon-size-16: 16px;
    --icon-size-20: 20px;
    --icon-size-24: 24px;
    --icon-size-32: 32px;
    --icon-size-40: 40px;
    --icon-size-48: 48px;
    --icon-size-64: 64px;
    --icon-size-96: 96px;

    /* radius */
    --radius-sm: 4px;
    --radius-md: 8px;
    --radius-lg: 12px;
    --radius-pill: 9999px;
}
shared/styles/tokens.css 93 lines
css
/*
 * Design tokens by role. Raw values come from palette.css (generated); which grey is a
 * border and which is muted text is decided here, and so would a dark mode be.
 */
:root {
    /* Text. `--ink*` is always a colour; `--text-*` is always a size. */
    --ink: var(--gray-950);
    /* Text that reads as done or in progress, a step lighter than a heading. */
    --ink-strong: var(--gray-800);
    /* Body copy: a step down from --ink. */
    --ink-soft: var(--gray-600);
    --ink-muted: var(--gray-500);
    --ink-subtle: var(--gray-400);
    /* What has not started yet. */
    --ink-faint: var(--gray-300);
    --ink-inverse: var(--gray-0);

    /* Backgrounds */
    --surface: var(--gray-0);
    --surface-muted: var(--gray-50);
    /* A well inside a surface: the filled shape a single icon sits in. */
    --surface-sunken: var(--gray-100);

    /* Outlines */
    --border: var(--gray-200);
    /* The edge of a box that already has a fill, such as an input. */
    --border-soft: var(--gray-100);
    --border-strong: var(--gray-300);
    --border-accent: var(--brand-400);

    /* Brand accent */
    --accent: var(--brand-500);
    --accent-strong: var(--brand-600);
    --accent-surface: var(--brand-100);
    /* The outline of a tinted box, or a small shape on one. */
    --accent-border: var(--brand-300);
    /* Text or a mark on either of the above. */
    --accent-ink: var(--brand-700);

    /* Status. Warning rides the brand ramp — that is what the designs use. */
    --success: var(--green-700);
    --success-surface: var(--green-100);
    --success-border: var(--green-300);

    --warning: var(--brand-500);
    --warning-surface: var(--brand-100);
    --warning-border: var(--brand-300);

    --danger: var(--red-700);
    --danger-surface: var(--red-100);
    --danger-border: var(--red-300);

    /* Icons. Fed straight into --lord-icon-* by the demos. */
    --icon-color: var(--gray-950);
    --icon-accent: var(--brand-500);

    /* Icon placeholders are black SVGs. Each filter turns black into the colour of the same
       name. Made with a CSS filter generator: make a new one when its colour changes. */
    --filter-ink: invert(2%) sepia(4%) saturate(4817%) hue-rotate(193deg) brightness(114%)
        contrast(96%);
    --filter-ink-soft: invert(33%) sepia(18%) saturate(323%) hue-rotate(182deg) brightness(100%)
        contrast(90%);
    --filter-ink-muted: invert(55%) sepia(23%) saturate(191%) hue-rotate(181deg) brightness(84%)
        contrast(89%);
    --filter-ink-subtle: invert(70%) sepia(11%) saturate(284%) hue-rotate(181deg) brightness(91%)
        contrast(86%);
    --filter-ink-faint: invert(76%) sepia(17%) saturate(99%) hue-rotate(184deg) brightness(99%)
        contrast(100%);
    --filter-ink-inverse: invert(100%);
    --filter-accent: invert(49%) sepia(65%) saturate(3508%) hue-rotate(337deg) brightness(106%)
        contrast(113%);
    --filter-accent-strong: invert(29%) sepia(85%) saturate(1790%) hue-rotate(350deg)
        brightness(94%) contrast(93%);
    --filter-success: invert(38%) sepia(22%) saturate(2045%) hue-rotate(94deg) brightness(92%)
        contrast(84%);
    --filter-warning: var(--filter-accent);
    --filter-danger: invert(48%) sepia(74%) saturate(7139%) hue-rotate(343deg) brightness(84%)
        contrast(105%);

    /* Type stacks. The families themselves are in palette.css. */
    --font-ui:
        var(--font-ui-name), 'Figtree fallback', -apple-system, BlinkMacSystemFont, 'Segoe UI',
        Roboto, sans-serif;
    --font-mono: var(--font-mono-name), ui-monospace, SFMono-Regular, Menlo, monospace;

    /* Side padding of a page. The portal uses the same value, so demo and text line up. */
    --gutter: clamp(var(--space-16), 5vw, var(--space-48));

    /* A card's halo: no offset, so it reads as lift rather than as a light source. */
    --shadow-sm: 0 0 7.5px color-mix(in srgb, var(--gray-400) 20%, transparent);
    /* The same halo under a brand-coloured element. */
    --shadow-accent: 0 0 7.5px color-mix(in srgb, var(--accent-strong) 40%, transparent);
}
shared/ui/pager.css 40 lines
css
/* The dots that page between the parts of a demo. Where they sit is the demo's business. */
.pager {
    display: flex;
    gap: var(--space-4);
}

/* A small dot inside a button big enough to hit. */
.pager__dot {
    display: grid;
    place-items: center;
    width: var(--space-24);
    height: var(--space-24);
    padding: 0;
    border: 0;
    background: none;
    cursor: pointer;
}

.pager__dot::before {
    content: '';
    width: var(--space-8);
    height: var(--space-8);
    border-radius: var(--radius-pill);
    background: var(--border-strong);
    transition: background 150ms ease;
}

.pager__dot:hover::before {
    background: var(--ink-subtle);
}

.pager__dot[aria-pressed='true']::before {
    background: var(--accent);
}

@media (prefers-reduced-motion: reduce) {
    .pager__dot::before {
        transition: none;
    }
}
shared/ui/pager.ts 21 lines
/**
 * Dots that switch between the parts of one demo. Demo scaffolding, not a control: it
 * exists so a demo can show three variants of a component without stacking them.
 *
 * Parts carry `data-page`, dots carry `.pager__dot`, both in source order. A hidden page is
 * out of the tab order and the accessibility tree.
 */
export function pager(root: ParentNode = document): (shown: number) => void {
    const pages = [...root.querySelectorAll<HTMLElement>('[data-page]')];
    const dots = [...root.querySelectorAll<HTMLButtonElement>('.pager__dot')];

    const show = (shown: number) => {
        pages.forEach((page, at) => (page.hidden = at !== shown));
        dots.forEach((dot, at) => dot.setAttribute('aria-pressed', String(at === shown)));
    };

    dots.forEach((dot, at) => dot.addEventListener('click', () => show(at)));
    show(0);

    return show;
}

Icons

Hover a preview to play it. The icons are under the Lordicon License Terms, not the MIT licence of the code.

Preview Used as Lordicon icon
puzzle-piece system-outline-3150-puzzle-piece (edited by hand)
rocket system-outline-489-rocket (edited by hand)
avatars-group system-outline-314-avatars-group (edited by hand)
check-circle-solid system-solid-24-check-circle (edited by hand)