17 KB gzipped 0 KB JavaScript MIT

Shine CSS framework

Ultra-light, pure-CSS framework: utility classes, ready-made components and master design knobs.

The whole framework is one stylesheet of 17 KB gzipped (measured with node build.js). Modals, drawers, dropdowns, tooltips and accordions run on native HTML, so there is nothing to compile and no script to load.

Drop it in your <head>

<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/asticore/shine@v1.0.0/dist/shine.min.css">

Welcome back

Styled with Shine classes only.

ALGHKJ
Tip Open the builder to restyle this card.

Theme builder

Design your theme with a few knobs

Shine reads everything from base tokens. Change a color, a corner level or the spacing unit and the whole preview follows. Copy the result as an <html> tag or a CSS block.

Presets
Brand colors
Shape and depth
Typography
Advanced: surface colors
Light surfaces
Dark surfaces
NewLiveBeta3 alerts

Ship a calmer dashboard

Every color, corner and shadow here comes from a handful of tokens. Move a slider and watch it update.

Revenue$48.2k+12% this month
Active users2,915+4.1% this week
Conversion3.8%-0.3% vs. last week

Create project

Letters and numbers only.
Enter a valid email.
Heads up Maintenance starts at 02:00 UTC.
Saved Your changes are live.
Almost full 92% of storage used.
Failed Payment was declined.
Recent invoices
InvoiceCustomerStatusAmount
#1042Ada LovelacePaid$1,200
#1043Grace HopperPending$860
#1044Alan TuringOverdue$2,450

Your <html> tag

<html lang="en">

CSS overrides

/* defaults, nothing overridden */

Only changed tokens are exported. Your settings are saved in this browser and encoded in the URL hash, so you can share the link.

Class playground

Edit HTML, inspect classes, test breakpoints

Pick a section template, edit the markup, then click any element in the preview to add or remove Shine classes. The preview uses your theme from the builder above.

Live preview (sandboxed iframe)

Class inspector

Click an element in the preview.
  • No element selected.

Components

Everything ready to use

Every example is live and styled with Shine alone. Open Code to copy the markup. Use the page theme switch in the header to check dark mode.

Buttons

btn btn-* tone-*
Code
<div class="stack gap-3 w-full">
  <div class="cluster gap-2"><button class="btn" type="button">Solid</button><button class="btn btn-outline" type="button">Outline</button><button class="btn btn-soft" type="button">Soft</button><button class="btn btn-ghost" type="button">Ghost</button><button class="btn btn-link" type="button">Link</button><button class="btn btn-icon" type="button" aria-label="Favorite">★</button></div>
  <div class="cluster gap-2"><button class="btn tone-secondary" type="button">Secondary</button><button class="btn tone-accent" type="button">Accent</button><button class="btn tone-success" type="button">Success</button><button class="btn tone-warning btn-soft" type="button">Warning</button><button class="btn tone-danger btn-outline" type="button">Danger</button><button class="btn tone-info btn-ghost" type="button">Info</button></div>
  <div class="cluster gap-2"><button class="btn btn-sm" type="button">Small</button><button class="btn" type="button">Default</button><button class="btn btn-lg" type="button">Large</button><button class="btn" type="button" disabled>Disabled</button></div>
  <button class="btn btn-block" type="button">Block button</button>
</div>

Button group & split button

btn-group btn-group-vertical btn-caret
Code
<div class="btn-group" role="group" aria-label="Text alignment"><button class="btn btn-outline" type="button">Left</button><button class="btn btn-outline" type="button">Center</button><button class="btn btn-outline" type="button">Right</button></div>
<div class="btn-group" role="group" aria-label="Save"><button class="btn" type="button">Save</button><button class="btn btn-caret" type="button" popovertarget="demo-split" aria-label="More save options"></button></div>
<div id="demo-split" popover class="menu dropdown-menu dropdown-menu-end"><a href="#demo-button-group">Save as…</a><a href="#demo-button-group">Export PDF</a></div>
<div class="btn-group-vertical" role="group" aria-label="Sort"><button class="btn" type="button">Newest</button><button class="btn" type="button">Popular</button><button class="btn" type="button">Rating</button></div>

Cards

card card-header card-body card-footer card-media

Header

Radius and elevation follow the knobs.

Flat with media

No elevation, stretched link.

Read more
Code
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4 w-full">
  <article class="card">
    <div class="card-header"><h4 class="card-title m-0">Header</h4></div>
    <div class="card-body">Radius and elevation follow the knobs.</div>
    <div class="card-footer cluster gap-2"><button class="btn btn-sm" type="button">Save</button><button class="btn btn-sm btn-ghost" type="button">Cancel</button></div>
  </article>
  <article class="card card-flat">
    <div class="card-media h-24 bg-primary" role="img" aria-label="Placeholder"></div>
    <div class="card-body"><h4 class="card-title m-0">Flat with media</h4><p class="text-muted text-sm m-0">No elevation, stretched link.</p><a class="stretched-link link text-sm" href="#components">Read more</a></div>
  </article>
</div>

Form controls

input select textarea checkbox radio switch range file
Helper text
Enter a valid email
Code
<form class="grid grid-cols-1 sm:grid-cols-2 gap-4 w-full" onsubmit="return false">
  <div class="field"><label class="label" for="g-name">Name</label><input class="input" id="g-name" placeholder="Ada Lovelace" autocomplete="off"><span class="hint">Helper text</span></div>
  <div class="field"><label class="label" for="g-mail">Email</label><input class="input is-invalid" id="g-mail" value="oops" aria-invalid="true" aria-describedby="g-mail-h"><span class="hint" id="g-mail-h">Enter a valid email</span></div>
  <div class="field"><label class="label" for="g-plan">Plan</label><select class="select" id="g-plan"><option>Free</option><option>Pro</option></select></div>
  <div class="field"><label class="label" for="g-lg">Large</label><input class="input input-lg" id="g-lg" placeholder="input-lg" autocomplete="off"></div>
  <div class="field sm:col-span-2"><label class="label" for="g-msg">Message</label><textarea class="textarea" id="g-msg" rows="2"></textarea></div>
  <div class="field"><label class="label" for="g-range">Volume</label><input class="range" type="range" id="g-range" value="40"></div>
  <div class="field"><label class="label" for="g-file">Upload</label><input class="file" type="file" id="g-file"></div>
  <div class="cluster gap-4 sm:col-span-2">
    <label class="flex items-center gap-2"><input type="checkbox" class="checkbox" checked> Checkbox</label>
    <label class="flex items-center gap-2"><input type="radio" class="radio" name="g-r" checked> Radio A</label>
    <label class="flex items-center gap-2"><input type="radio" class="radio" name="g-r"> Radio B</label>
    <label class="flex items-center gap-2"><input type="checkbox" class="switch" checked> Switch</label>
  </div>
</form>

Input group and floating labels

input-group input-addon floating
@
Code
<div class="stack gap-4 w-full">
  <div class="input-group"><span class="input-addon">@</span><label class="sr-only" for="g-user">Username</label><input class="input" id="g-user" placeholder="username" autocomplete="off"></div>
  <div class="input-group"><label class="sr-only" for="g-search">Search</label><input class="input" id="g-search" placeholder="Search components" autocomplete="off"><button class="btn" type="button">Search</button></div>
  <div class="floating"><input class="input" id="g-fl1" placeholder=" " autocomplete="off"><label for="g-fl1">Full name</label></div>
  <div class="floating"><textarea class="textarea" id="g-fl2" placeholder=" " rows="2"></textarea><label for="g-fl2">Notes</label></div>
</div>

Badges, avatars, kbd

badge avatar avatar-group dot indicator kbd
DefaultSuccessSolidOutline Pending
ABCD
ALGHKJ+4
3 Press Ctrl + K
Code
<div class="stack gap-4 w-full">
  <div class="cluster gap-2"><span class="badge">Default</span><span class="badge tone-success">Success</span><span class="badge badge-solid tone-danger">Solid</span><span class="badge badge-outline tone-info">Outline</span><span class="badge tone-warning"><span class="dot tone-warning"></span> Pending</span></div>
  <div class="cluster gap-4">
    <span class="avatar">AB</span><span class="avatar tone-accent">CD</span>
    <div class="avatar-group"><span class="avatar">AL</span><span class="avatar tone-accent">GH</span><span class="avatar tone-success">KJ</span><span class="avatar tone-secondary">+4</span></div>
    <span class="indicator"><span class="indicator-item badge badge-solid tone-danger">3</span><button class="btn btn-outline" type="button">Inbox</button></span>
    <span>Press <kbd class="kbd">Ctrl</kbd> + <kbd class="kbd">K</kbd></span>
  </div>
</div>

Alerts

alert alert-solid alert-title
Info A soft alert.
Success Your changes were saved.
Warning Check your input.
Danger Something failed.
Code
<div class="stack gap-3 w-full">
  <div class="alert tone-info"><span class="alert-title">Info</span> A soft alert.</div>
  <div class="alert alert-solid tone-success"><span class="alert-title">Success</span> Your changes were saved.</div>
  <div class="alert alert-solid tone-warning"><span class="alert-title">Warning</span> Check your input.</div>
  <div class="alert alert-solid tone-danger"><span class="alert-title">Danger</span> Something failed.</div>
</div>

Modal

modal modal-header modal-body modal-footer
Code
<button class="btn" type="button" command="show-modal" commandfor="g-modal">Open modal</button>
<dialog id="g-modal" class="modal" aria-labelledby="g-modal-t">
  <div class="modal-header"><h4 class="card-title m-0" id="g-modal-t">Modal title</h4><button class="btn-close" type="button" command="close" commandfor="g-modal" aria-label="Close"></button></div>
  <div class="modal-body">Native dialog: Esc or the backdrop closes it and focus is trapped by the browser.</div>
  <div class="modal-footer"><button class="btn btn-ghost" type="button" command="close" commandfor="g-modal">Cancel</button><button class="btn" type="button" command="close" commandfor="g-modal">OK</button></div>
</dialog>

Offcanvas

offcanvas offcanvas-right offcanvas-top offcanvas-bottom
Code
<button class="btn btn-outline" type="button" popovertarget="g-oc">Left panel</button>
<button class="btn btn-outline" type="button" popovertarget="g-oc2">Right panel</button>
<aside id="g-oc" popover class="offcanvas" aria-label="Left panel">
  <div class="offcanvas-header"><strong>Menu</strong><button class="btn-close" type="button" popovertarget="g-oc" popovertargetaction="hide" aria-label="Close"></button></div>
  <div class="offcanvas-body"><ul class="menu"><li><a href="#components">Dashboard</a></li><li><a href="#components">Projects</a></li><li><a href="#components">Settings</a></li></ul></div>
</aside>
<aside id="g-oc2" popover class="offcanvas offcanvas-right" aria-label="Right panel">
  <div class="offcanvas-header"><strong>Filters</strong><button class="btn-close" type="button" popovertarget="g-oc2" popovertargetaction="hide" aria-label="Close"></button></div>
  <div class="offcanvas-body">Built on the Popover API.</div>
</aside>

Dropdowns

dropdown menu dropdown-menu
Code
<details class="dropdown"><summary class="btn btn-soft">Details dropdown</summary>
  <ul class="menu"><li><a href="#components" class="active">Profile</a></li><li><a href="#components">Settings</a></li><li><hr class="menu-divider"></li><li><button type="button">Sign out</button></li></ul></details>
<button class="btn btn-outline" type="button" popovertarget="g-pop">Popover menu</button>
<div id="g-pop" popover class="menu dropdown-menu"><ul class="list-none p-0 m-0"><li><a href="#components">Duplicate</a></li><li><a href="#components">Archive</a></li><li><button type="button">Delete</button></li></ul></div>

Tooltip and toast

data-tooltip toast
Saved. Your changes are live.
A static toast is just a notice card.
Code
<button class="btn btn-outline" type="button" data-tooltip="Top tooltip">Top</button>
<button class="btn btn-outline" type="button" data-tooltip="Bottom tooltip" data-tooltip-pos="bottom">Bottom</button>
<button class="btn btn-outline" type="button" data-tooltip="Right tooltip" data-tooltip-pos="right">Right</button>
<button class="btn tone-success" type="button" popovertarget="g-toast">Show toast</button>
<div id="g-toast" popover="manual" class="toast tone-success" role="status"><strong>Saved.</strong> Your changes are live. <button class="btn-close" type="button" popovertarget="g-toast" popovertargetaction="hide" aria-label="Dismiss"></button></div>
<div class="toast tone-info w-full">A static toast is just a notice card.</div>

Navbar

navbar navbar-brand navbar-nav navbar-end
Code
<nav class="navbar border rounded-lg w-full" aria-label="Demo navbar"><a class="navbar-brand" href="#components">Brand</a>
  <ul class="navbar-nav"><li><a href="#components" aria-current="page">Home</a></li><li><a href="#components">Docs</a></li><li><a href="#components">Pricing</a></li></ul>
  <a class="navbar-end btn btn-sm" href="#components">Sign in</a></nav>

Breadcrumb and pagination

breadcrumb pagination
Code
<div class="stack gap-4 w-full">
  <nav aria-label="Breadcrumb"><ol class="breadcrumb"><li><a href="#components">Home</a></li><li><a href="#components">Library</a></li><li aria-current="page">Data</li></ol></nav>
  <nav aria-label="Pagination"><ul class="pagination"><li><span aria-disabled="true">Prev</span></li><li><a href="#components">1</a></li><li><a href="#components" aria-current="page">2</a></li><li><a href="#components">3</a></li><li><a href="#components">Next</a></li></ul></nav>
</div>

Tabs

tabs tabs-pills
Code
<div class="stack gap-4 w-full">
  <ul class="tabs"><li><a href="#components" aria-current="page">Overview</a></li><li><a href="#components">Usage</a></li><li><a href="#components">API</a></li></ul>
  <ul class="tabs tabs-pills"><li><a href="#components" aria-current="page">Day</a></li><li><a href="#components">Week</a></li><li><a href="#components">Month</a></li></ul>
</div>

Accordion

accordion
What is Shine?

A single prebuilt stylesheet with utilities, components and design knobs.

Does it need JavaScript?

No. Native details, dialog and popover elements do the work.

Can I override it?

Yes. Shine lives in cascade layers, so your CSS always wins.

Code
<div class="accordion w-full">
  <details name="g-acc" open><summary>What is Shine?</summary><p>A single prebuilt stylesheet with utilities, components and design knobs.</p></details>
  <details name="g-acc"><summary>Does it need JavaScript?</summary><p>No. Native details, dialog and popover elements do the work.</p></details>
  <details name="g-acc"><summary>Can I override it?</summary><p>Yes. Shine lives in cascade layers, so your CSS always wins.</p></details>
</div>

Table

table table-striped table-hover table-bordered table-stack table-wrap
Sort arrows come from aria-sort (your JS sorts); rows stack into cards on phones.
NameRoleStatusCommits
Ada LovelaceEngineerActive1,204
Grace HopperAdmiralAway982
Alan TuringResearcherSelected640
Total2,826
PlanPrice
Starter$0
LegacyRetiring
Code
<div class="table-wrap w-full"><table class="table table-striped table-hover table-stack">
  <caption>Sort arrows come from aria-sort (your JS sorts); rows stack into cards on phones.</caption>
  <thead><tr><th scope="col" aria-sort="ascending">Name</th><th scope="col" aria-sort="none">Role</th><th scope="col">Status</th><th scope="col" class="text-right">Commits</th></tr></thead>
  <tbody>
    <tr><td data-label="Name">Ada Lovelace</td><td data-label="Role">Engineer</td><td data-label="Status"><span class="badge tone-success">Active</span></td><td data-label="Commits" class="text-right">1,204</td></tr>
    <tr class="tone-warning"><td data-label="Name">Grace Hopper</td><td data-label="Role">Admiral</td><td data-label="Status"><span class="badge tone-warning">Away</span></td><td data-label="Commits" class="text-right">982</td></tr>
    <tr aria-selected="true"><td data-label="Name">Alan Turing</td><td data-label="Role">Researcher</td><td data-label="Status"><span class="badge tone-info">Selected</span></td><td data-label="Commits" class="text-right">640</td></tr>
  </tbody>
  <tfoot><tr><td>Total</td><td></td><td></td><td class="text-right">2,826</td></tr></tfoot>
</table></div>
<table class="table table-bordered table-compact w-full">
  <thead><tr><th scope="col">Plan</th><th scope="col" class="text-right">Price</th></tr></thead>
  <tbody><tr><td>Starter</td><td class="text-right">$0</td></tr><tr class="tone-danger"><td>Legacy</td><td class="text-right">Retiring</td></tr></tbody>
</table>

Progress, meter, stat

progress meter stat
60%
55%
Visitors12.4k+8% vs. last week
Bounce rate32%-2.1 pts
Code
<div class="stack gap-4 w-full">
  <div><label class="label" for="g-prog">Uploading</label><progress class="progress" id="g-prog" value="60" max="100">60%</progress></div>
  <div><label class="label" for="g-meter">Disk usage</label><meter class="meter" id="g-meter" min="0" max="100" low="40" high="80" optimum="20" value="55">55%</meter></div>
  <div class="grid grid-cols-2 gap-4"><div class="stat"><span class="stat-label">Visitors</span><span class="stat-value">12.4k</span><span class="stat-desc">+8% vs. last week</span></div><div class="stat"><span class="stat-label">Bounce rate</span><span class="stat-value">32%</span><span class="stat-desc">-2.1 pts</span></div></div>
</div>

List group

list-group
  • Inbox12
  • Drafts3
  • Sent48
Code
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4 w-full">
  <div class="list-group"><a href="#components" aria-current="true">Active item</a><a href="#components">Second item</a><a href="#components">Third item</a></div>
  <ul class="list-group"><li class="flex justify-between"><span>Inbox</span><span class="badge">12</span></li><li class="flex justify-between"><span>Drafts</span><span class="badge tone-warning">3</span></li><li class="flex justify-between"><span>Sent</span><span class="badge tone-success">48</span></li></ul>
</div>
carousel carousel-peek carousel-hide-bar
Code
<div class="carousel rounded-lg w-full" tabindex="0" role="group" aria-roledescription="carousel" aria-label="Demo slides">
  <div class="demo-slide tone-primary bg-primary">Slide 1</div><div class="demo-slide tone-accent bg-accent">Slide 2</div><div class="demo-slide tone-success bg-success">Slide 3</div>
</div>

Layout primitives

stack cluster center section grid divider vr
.stackonetwothree
.clusteronetwothreefour
.grid grid-cols-1 md:grid-cols-3
or
leftright
Code
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 w-full">
  <div class="stack gap-2 p-4 bg-surface-2 rounded-lg"><strong>.stack</strong><span class="badge">one</span><span class="badge">two</span><span class="badge">three</span></div>
  <div class="cluster gap-2 p-4 bg-surface-2 rounded-lg"><strong>.cluster</strong><span class="badge">one</span><span class="badge">two</span><span class="badge">three</span><span class="badge">four</span></div>
  <div class="p-4 bg-surface-2 rounded-lg"><strong>.grid grid-cols-1 md:grid-cols-3</strong><div class="divider">or</div><div class="flex items-center gap-3 h-8"><span>left</span><span class="vr"></span><span>right</span></div></div>
</div>

Layout & sections

banner eyebrow display-1 segmented grid-hairline full-bleed

Layout

Fluid headings

  • One
  • Two
  • Three
.full-bleed band (stretches edge to edge on a real page)
Code
<div class="banner tone-accent w-full"><span>Shine 1.1 is out.</span><a href="#components">See what is new</a></div>
<div class="stack gap-2 w-full"><p class="eyebrow m-0">Layout</p><h4 class="display-3 m-0">Fluid headings</h4></div>
<div class="segmented" role="radiogroup" aria-label="Billing period"><label><input type="radio" name="g-billing" checked> Monthly</label><label><input type="radio" name="g-billing"> Yearly</label></div>
<ul class="grid grid-cols-1 sm:grid-cols-3 grid-hairline list-none p-0 m-0 w-full"><li class="p-4">One</li><li class="p-4">Two</li><li class="p-4">Three</li></ul>
<div class="full-bleed bg-surface-2 py-6 text-center">Full-bleed band</div>

Why Shine

Small enough to forget about

One stylesheet, a few knobs, and your own CSS always wins.

  • Master knobs

    Brand color, theme, corner level, shadow depth and density set once on <html>. Everything follows.

  • Utilities without a compiler

    Write flex, p-4 and md:grid-cols-3 straight in your HTML. Nothing to install.

  • Components without JavaScript

    Modals, drawers, dropdowns, tooltips, toasts, accordions: native dialog, popover and details.

  • 17 KB gzipped

    Smaller than most hero images. Trim it further with node build.js --only=....

  • Accessible by default

    Semantic HTML targets, visible focus rings, a skip link, reduced-motion and print styles.

  • No specificity fights

    Built on CSS cascade layers: your unlayered CSS beats Shine without !important.