PaperCSS Framework

Lightweight collection of classes & components styled like layered paper cards. Responsive, a11y‑friendly, with light/dark mode – ready to drop in.

Components

πŸš€ Quick Start

PaperCSS is a lightweight CSS framework inspired by e‑ink and paper document aesthetics. Each section has a </> button that reveals usage code. Click to inspect implementation.

Basic Installation

Add to HTML:

<link rel="stylesheet" href="paper.css">

Styles apply globally; wrap content in optional containers/cards.

πŸ’‘ Full skeleton:
<!DOCTYPE html>
<html lang="en" data-theme="light">
<head>
  <link rel="stylesheet" href="paper.css" />
</head>
<body>
  <div class="container">
    <div class="card">Your content</div>
  </div>
  <script src="paper.js"></script>
</body>
</html>

πŸ“ Typography & Basics

Responsive fluid scale, semantic headings and helpful utility classes.

Heading Scale

H1 Main Title

H2 Section

H3 Subsection

H4 Smaller Heading

H5 Lead Text
H6 Meta Info
πŸ’‘ Headings:
<h1>H1 Main Title</h1>
<h2>H2 Section</h2>
<h3>H3 Subsection</h3>
<h4>H4 Smaller Heading</h4>
<h5>H5 Lead Text</h5>
<h6>H6 Meta Info</h6>

Paragraph & Inline Elements

This framework uses CSS Variables, a fluid scale and spacing utilities.

<div class="card layered">Card content</div>

Switch theme using data-theme="dark" on <html>.

πŸ’‘ Text & code:
<p>Normal paragraph with <code>inline code</code></p>
<p class="text-muted">Muted text</p>
<pre><code>Code block</code></pre>
<p class="text-center">Centered</p>
<p class="text-right">Right aligned</p>

🎨 Palette & CSS Variables

Override design tokens via CSS variables. Automatic light/dark adaptation.

Core Colors

Base
Accent
Success
Info
Warning
Danger
πŸ’‘ Override:
:root {
  --paper-accent: #346cab;
  --paper-accent-hover: #3e79bd;
  --paper-success: #28a745;
  --paper-warning: #ffc107;
  --paper-danger: #dc3545;
  --paper-info: #17a2b8;
}
[data-theme="dark"] {
  --paper-bg: #1a1a1a;
  --paper-ink: #e8e4d9;
}

πŸ”˜ Button System

Variants, semantic colors & effects.

Base Buttons

πŸ’‘ Basic buttons:
<button class="btn">Primary</button>
<button class="btn btn-secondary">Secondary</button>
<button class="btn btn-outline">Outline</button>
<button class="btn btn-ghost">Ghost</button>

Semantic Variants

πŸ’‘ Semantic:
<button class="btn btn-success">Success</button>
<button class="btn btn-info">Info</button>
<button class="btn btn-warning">Warning</button>
<button class="btn btn-danger">Danger</button>

🧩 Core Components (Excerpt)

Translate & adapt remaining Polish demo sections similarly if needed.

See Polish `index.html` for full extended showcase (alerts, tabs, accordion, etc.).

πŸ†• New Components

Latest additions to the PaperCSS framework - modern interactive components with paper-style aesthetics.

Skeleton Loading

Placeholder animation while content is loading.

This is normal content with text and images.

More content to hide behind skeleton.

πŸ’‘ Skeleton Loading - usage example:
<!-- HTML - content container -->
<div id="content-demo">
  <p>Content to hide behind skeleton</p>
  <div class="user-avatar"></div>
  <p>More content</p>
</div>

<!-- Control buttons -->
<button onclick="PaperSkeleton.show('#content-demo')">
  Show skeleton
</button>
<button onclick="PaperSkeleton.hide('#content-demo')">
  Hide skeleton
</button>

<!-- JavaScript API -->
<script>
// Show skeleton on element
PaperSkeleton.show('#content-demo');

// Hide skeleton and restore content
PaperSkeleton.hide('#content-demo');

// Auto-hide after timeout
setTimeout(() => PaperSkeleton.hide('#content-demo'), 3000);
</script>

Offcanvas Panel

Side panel sliding from screen edge with animation and scroll lock.

πŸ’‘ Offcanvas Panel - usage example:
<!-- Trigger button -->
<button class="btn btn-primary" data-open-offcanvas="demo-offcanvas">
  Open panel
</button>

<!-- Offcanvas structure -->
<div class="offcanvas-backdrop" id="demo-offcanvas-backdrop">
  <div class="offcanvas" id="demo-offcanvas">
    <div class="offcanvas-header">
      <h3>Panel title</h3>
      <button class="offcanvas-close btn-ghost">&times;</button>
    </div>
    <div class="offcanvas-body">
      <p>Side panel content</p>
      <ul>
        <li>Option 1</li>
        <li>Option 2</li>
        <li>Option 3</li>
      </ul>
      <div class="mt-4">
        <button class="btn btn-primary">Save</button>
        <button class="btn btn-outline">Cancel</button>
      </div>
    </div>
  </div>
</div>

<!-- JavaScript - automatic with data-open-offcanvas -->

Dropdown Menu

Dropdown menu with keyboard support and animations.

πŸ’‘ Dropdown Menu - usage example:
<!-- Dropdown with button and menu -->
<div class="dropdown">
  <button class="btn btn-secondary" data-dropdown-toggle>
    Menu options β–Ό
  </button>
  <ul class="dropdown-menu">
    <li><a href="#" class="dropdown-item">βš™οΈ Settings</a></li>
    <li><a href="#" class="dropdown-item">πŸ‘€ Profile</a></li>
    <li><hr class="dropdown-divider"></li>
    <li><a href="#" class="dropdown-item">πŸšͺ Logout</a></li>
  </ul>
</div>

<!-- Different button styles -->
<div class="dropdown">
  <button class="btn btn-outline" data-dropdown-toggle>
    More β‹―
  </button>
  <ul class="dropdown-menu">
    <li><a href="#" class="dropdown-item">Edit</a></li>
    <li><a href="#" class="dropdown-item">Delete</a></li>
  </ul>
</div>

<!-- Automatic handling via data-dropdown-toggle -->

Chip/Tag System

Interactive tags with removal capability and different styles.

React
JavaScript
CSS
HTML
πŸ’‘ Chip/Tag System - usage example:
<!-- Chip/tag group -->
<div class="chip-group">
  <!-- Basic chip -->
  <div class="chip">
    <span>React</span>
    <button class="chip-close">&times;</button>
  </div>
  
  <!-- Outlined chip -->
  <div class="chip chip-outlined">
    <span>JavaScript</span>
    <button class="chip-close">&times;</button>
  </div>
  
  <!-- Small chip -->
  <div class="chip chip-small">
    <span>CSS</span>
    <button class="chip-close">&times;</button>
  </div>
  
  <!-- Chip without close button -->
  <div class="chip">
    <span>HTML</span>
  </div>
</div>

<!-- JavaScript for chip removal -->
<script>
// Auto-removal on .chip-close click
document.addEventListener('click', (e) => {
  if (e.target.classList.contains('chip-close')) {
    e.target.closest('.chip').remove();
  }
});
</script>

Progress Bars

Progress bars with animated filling and different styles.

Basic progress bars

πŸ’‘ Progress Bars - usage example:
<!-- Basic progress bar -->
<div class="progress-container">
  <div class="progress-bar" id="progress1" style="width: 0%"></div>
</div>

<!-- Colored variants -->
<div class="progress-container">
  <div class="progress-bar progress-success" style="width: 75%"></div>
</div>
<div class="progress-container">
  <div class="progress-bar progress-warning" style="width: 60%"></div>
</div>
<div class="progress-container">
  <div class="progress-bar progress-danger" style="width: 30%"></div>
</div>

<!-- Progress with label -->
<div class="flex justify-between items-center mb-1">
  <label class="text-sm text-muted">Downloading file</label>
  <span class="text-sm text-muted" id="progress-label">0%</span>
</div>
<div class="progress-container">
  <div class="progress-bar progress-info" id="progress" style="width: 0%"></div>
</div>

<!-- Thin progress bars -->
<div class="progress-container progress-thin">
  <div class="progress-bar" style="width: 40%"></div>
</div>
<div class="progress-container progress-xs">
  <div class="progress-bar progress-success" style="width: 70%"></div>
</div>

<!-- JavaScript API -->
<script>
// Animate progress bar
PaperProgress.animate('#progress', 75, 2000);

// With callback after completion
PaperProgress.animate('#progress', 100, 1500, () => {
  console.log('Progress complete!');
});
</script>

βž• Additional Components

Extra interactive components for enhanced user experience - tooltips, alerts, loading states, and more.

Tooltip System

Contextual tooltips displayed on hover or keyboard focus.

Basic tooltips

Other elements with tooltips

New Info πŸ“š Documentation .card
Tip: Tooltips work on both mouse hover and keyboard focus (Tab). They automatically position themselves to stay visible on screen.
πŸ’‘ Tooltip System - usage example:
<!-- Basic tooltips -->
<button class="btn btn-primary" data-tooltip="Main action button">
  Primary Button
</button>
<button class="btn btn-success" data-tooltip="Operation successful">
  βœ“ Success
</button>

<!-- Tooltips on other elements -->
<span class="badge" data-tooltip="Status information">New</span>
<code data-tooltip="CSS class description">.card</code>
<a href="#" data-tooltip="Link description">Link text</a>

<!-- Icon buttons with tooltips -->
<button class="btn btn-outline" data-tooltip="Application settings">
  βš™οΈ
</button>
<button class="btn btn-outline" data-tooltip="User profile">
  πŸ‘€
</button>
<button class="btn btn-outline" data-tooltip="Notifications">
  πŸ””
</button>

<!-- Automatic positioning and keyboard support included -->

Alert/Banner System

Static and dynamic alert components for user notifications.

Info: This is an informational alert with close option.
Success: Operation completed successfully.
Warning: Please check your input data.
Error: Processing problem occurred.
πŸ’‘ Alert/Banner System - usage example:
<!-- Static alerts -->
<div class="alert alert-info">
  <strong>Info:</strong> Informational message.
</div>
<div class="alert alert-success">
  <strong>Success:</strong> Operation successful.
</div>
<div class="alert alert-warning">
  <strong>Warning:</strong> Check your input.
</div>
<div class="alert alert-error">
  <strong>Error:</strong> Something went wrong.
</div>

<!-- Dismissible alerts -->
<div class="alert alert-info alert-dismissible">
  <strong>Info:</strong> This alert can be closed.
  <button class="alert-close">&times;</button>
</div>

<!-- Dynamic alerts with JavaScript -->
<script>
function showDynamicAlert(message, type, dismissible) {
  const container = document.getElementById('alerts-container');
  const alert = document.createElement('div');
  alert.className = `alert alert-${type}${dismissible ? ' alert-dismissible' : ''}`;
  alert.innerHTML = `
    <strong>${type.charAt(0).toUpperCase() + type.slice(1)}:</strong> ${message}
    ${dismissible ? '<button class="alert-close">&times;</button>' : ''}
  `;
  container.appendChild(alert);
}
</script>

Loading States

Various loading states in e-ink style.

Loading...
πŸ’‘ Loading States - usage example:
<!-- Dots loading animation -->
<div class="loading-dots">
  <span></span>
  <span></span>
  <span></span>
</div>

<!-- Spinner loading -->
<div class="loading-spinner"></div>

<!-- Pulse loading -->
<div class="loading-pulse"></div>

<!-- Loading text -->
<span class="text-muted">Loading...</span>

<!-- Usage in buttons -->
<button class="btn" disabled>
  <div class="loading-dots">
    <span></span>
    <span></span>
    <span></span>
  </div>
  Loading...
</button>

Empty State

πŸ“„

No Data

No items found to display. Add a new item or change your search filters.

πŸ’‘ Empty State - usage example:
<!-- Empty state component -->
<div class="empty-state">
  <div class="empty-state-icon">πŸ“„</div>
  <h3>No Data</h3>
  <p>No items found to display. Add a new item or change your search filters.</p>
  <button class="btn btn-primary">Add Item</button>
</div>

<!-- Different empty states -->
<div class="empty-state">
  <div class="empty-state-icon">πŸ”</div>
  <h3>No Search Results</h3>
  <p>We couldn't find anything matching your search.</p>
  <button class="btn btn-outline">Clear Search</button>
</div>

<div class="empty-state">
  <div class="empty-state-icon">πŸ“‹</div>
  <h3>No Tasks</h3>
  <p>You're all caught up! No tasks to complete.</p>
  <button class="btn btn-primary">Add New Task</button>
</div>

πŸ“Š Data Tables

Responsive tables with paper-style design, pagination, and sorting capabilities.

Data Table with Actions

# Name Status Tag Actions
01 Alpha Element New .alpha
02 Beta Element Info .beta
03 Gamma Element New .gamma
πŸ’‘ Data table with pagination:
<!-- Table wrapper for responsiveness -->
<div class="table-wrapper">
  <table>
    <thead>
      <tr>
        <th>#</th>
        <th>Name</th>
        <th>Status</th>
        <th>Actions</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>01</td>
        <td>Element Name</td>
        <td><span class="badge">New</span></td>
        <td>
          <button class="btn btn-ghost" data-tooltip="Preview">πŸ‘</button>
          <button class="btn btn-ghost" data-tooltip="Edit">✎</button>
          <button class="btn btn-ghost" data-tooltip="Delete">πŸ—‘</button>
        </td>
      </tr>
    </tbody>
  </table>
</div>

<!-- Pagination -->
<nav class="pagination">
  <button disabled>&laquo;</button>
  <button class="active">1</button>
  <button>2</button>
  <button>3</button>
  <button>&raquo;</button>
</nav>

<!-- Breadcrumb navigation -->
<nav class="breadcrumb" aria-label="breadcrumb">
  <a href="#">Home</a> <span>/</span>
  <a href="#">Section</a> <span>/</span>
  <span>Current</span>
</nav>

πŸ“ Forms with States

Complete form system with validation states, field types, and paper-style inputs.

Form with Validation States

Looks good!
Please check the format.
Too short.
Select user role.
Optional field.
πŸ’‘ Forms with validation states:
<form class="maxw-md">
  <!-- Success state -->
  <div class="form-group field-success">
    <label for="name">First Name</label>
    <input type="text" id="name" placeholder="Enter name" />
    <div class="help-text">Looks good!</div>
  </div>
  
  <!-- Warning state -->
  <div class="form-group field-warning">
    <label for="email">Email</label>
    <input type="email" id="email" />
    <div class="help-text">Check format.</div>
  </div>
  
  <!-- Error state -->
  <div class="form-group field-danger">
    <label for="password">Password</label>
    <input type="password" id="password" />
    <div class="help-text">Too short.</div>
  </div>
  
  <!-- Select with info state -->
  <div class="form-group field-info">
    <label for="role">Role</label>
    <select id="role">
      <option>Choose...</option>
      <option>Admin</option>
      <option>User</option>
    </select>
    <div class="help-text">Select role.</div>
  </div>
  
  <!-- Textarea -->
  <div class="form-group">
    <label for="message">Message</label>
    <textarea id="message" rows="4"></textarea>
    <div class="help-text">Optional.</div>
  </div>
  
  <!-- Inline fields -->
  <div class="form-group input-inline">
    <div>
      <label for="inline1">Field 1</label>
      <input type="text" id="inline1" />
    </div>
    <div>
      <label for="inline2">Field 2</label>
      <input type="text" id="inline2" />
    </div>
  </div>
  
  <div class="form-actions">
    <button type="submit" class="btn">Submit</button>
    <button type="reset" class="btn btn-outline">Reset</button>
  </div>
</form>

πŸ”§ Useful Components

Modern UI components that make building applications much easier – toggle switches, timeline, date picker and more.

Toggle Switches

Modern toggle switches in paper style with animations.

Basic switches

Standard (on)
Standard (off)
Success
Warning
Danger

Sizes

πŸ’‘ Toggle Switches - usage example:
<!-- Basic toggle -->
<label class="switch">
  <input type="checkbox">
  <span class="switch-slider"></span>
</label>

<!-- Color variants -->
<label class="switch switch-success">
  <input type="checkbox" checked>
  <span class="switch-slider"></span>
</label>
<label class="switch switch-warning">
  <input type="checkbox" checked>
  <span class="switch-slider"></span>
</label>
<label class="switch switch-danger">
  <input type="checkbox" checked>
  <span class="switch-slider"></span>
</label>
<label class="switch switch-info">
  <input type="checkbox" checked>
  <span class="switch-slider"></span>
</label>

<!-- Different sizes -->
<label class="switch switch-sm">
  <input type="checkbox">
  <span class="switch-slider"></span>
</label>
<label class="switch switch-lg">
  <input type="checkbox">
  <span class="switch-slider"></span>
</label>

<!-- Disabled -->
<label class="switch">
  <input type="checkbox" disabled>
  <span class="switch-slider"></span>
</label>

Timeline

Paper-style timeline for chronological presentation.

First framework version
January 2024
Launch of basic PaperCSS version with component system.
Dark mode added
March 2024
Implementation of automatic switching between light and dark modes.
New components
September 2024
Addition of advanced components: toggle switches, timeline, date picker.
πŸ’‘ Timeline - usage example:
<div class="timeline">
  <div class="timeline-item">
    <div class="timeline-header">
      <div class="timeline-title">Event title</div>
      <div class="timeline-date">January 2024</div>
    </div>
    <div class="timeline-content">
      Event description in timeline.
    </div>
  </div>
  
  <div class="timeline-item timeline-success">
    <div class="timeline-header">
      <div class="timeline-title">Success</div>
      <div class="timeline-date">March 2024</div>
    </div>
    <div class="timeline-content">
      Positive event.
    </div>
  </div>
  
  <div class="timeline-item timeline-warning">
    <div class="timeline-header">
      <div class="timeline-title">Warning</div>
      <div class="timeline-date">April 2024</div>
    </div>
    <div class="timeline-content">
      Event requiring attention.
    </div>
  </div>
  
  <div class="timeline-item timeline-danger">
    <div class="timeline-header">
      <div class="timeline-title">Issue</div>
      <div class="timeline-date">May 2024</div>
    </div>
    <div class="timeline-content">
      Critical event.
    </div>
  </div>
</div>

Date Picker

Paper-style date picker with calendar.

September 2024
Mo
Tu
We
Th
Fr
Sa
Su
Demo: This is a fully functional date picker! Click the field above, navigate between months and select dates.
πŸ’‘ Date Picker - usage example:
<div class="date-picker">
  <input type="text" class="date-picker-input" placeholder="Select date" readonly>
  <div class="date-picker-calendar">
    <div class="date-picker-header">
      <button class="date-picker-nav" data-action="prev">β€Ή</button>
      <div class="date-picker-month"></div>
      <button class="date-picker-nav" data-action="next">β€Ί</button>
    </div>
    <div class="date-picker-grid">
      <div class="date-picker-weekday">Mo</div>
      <div class="date-picker-weekday">Tu</div>
      <div class="date-picker-weekday">We</div>
      <div class="date-picker-weekday">Th</div>
      <div class="date-picker-weekday">Fr</div>
      <div class="date-picker-weekday">Sa</div>
      <div class="date-picker-weekday">Su</div>
      <!-- Days generated by JavaScript -->
    </div>
  </div>
</div>

<!-- Include JavaScript -->
<script src="datepicker.js"></script>

<!-- Auto-initialization - all .date-picker elements become active -->
<!-- Or manual initialization: -->
<script>
// Basic usage
const picker1 = new PaperDatePicker('#date-input');

// With options
const picker2 = new PaperDatePicker('#date-input-2', {
  format: 'MM/DD/YYYY',
  minDate: new Date(),
  maxDate: new Date(2025, 11, 31),
  onSelect: function(date) {
    console.log('Selected date:', date);
  }
});

// Set date programmatically
picker1.setDate(new Date());

// Get selected date
console.log(picker1.getDate());
</script>

Sidebar Navigation

Side navigation panel with animations and grouping.

Demo: Click the button above to see the sidebar in action. Panel will slide in from the left side of the screen.
πŸ’‘ Sidebar Navigation - usage example:
<!-- Open button -->
<button onclick="openSidebar()">Open menu</button>

<!-- Sidebar structure -->
<div class="sidebar-overlay" id="sidebar-overlay"></div>
<div class="sidebar" id="sidebar">
  <div class="sidebar-header">
    <h3 class="sidebar-title">Menu</h3>
  </div>
  
  <nav class="sidebar-nav">
    <div class="sidebar-nav-group">
      <div class="sidebar-nav-group-title">Main</div>
      <a href="#" class="sidebar-nav-item active">Dashboard</a>
      <a href="#" class="sidebar-nav-item">Projects</a>
      <a href="#" class="sidebar-nav-item">Tasks</a>
    </div>
    
    <div class="sidebar-nav-group">
      <div class="sidebar-nav-group-title">Settings</div>
      <a href="#" class="sidebar-nav-item">Profile</a>
      <a href="#" class="sidebar-nav-item">Preferences</a>
    </div>
  </nav>
</div>

<!-- JavaScript -->
<script>
function openSidebar() {
  document.getElementById('sidebar').classList.add('open');
  document.getElementById('sidebar-overlay').classList.add('open');
}

function closeSidebar() {
  document.getElementById('sidebar').classList.remove('open');
  document.getElementById('sidebar-overlay').classList.remove('open');
}

// Close on overlay click
document.getElementById('sidebar-overlay').addEventListener('click', closeSidebar);
</script>

Advanced Grid System

Extended grid system with more layout possibilities.

Grid with different columns

1
2
3
A
B
C
D

Column spans

span 2
span 3
1
span full
πŸ’‘ Advanced Grid System - usage example:
<!-- Basic grids -->
<div class="grid grid-2 gap-3">
  <div>Element 1</div>
  <div>Element 2</div>
</div>

<div class="grid grid-3 gap-4">
  <div>Element 1</div>
  <div>Element 2</div>
  <div>Element 3</div>
</div>

<!-- Grid with column spans -->
<div class="grid grid-6 gap-3">
  <div class="col-span-2">Takes 2 columns</div>
  <div class="col-span-3">Takes 3 columns</div>
  <div>1 column</div>
  <div class="col-span-full">Full width</div>
</div>

<!-- 12-column grid -->
<div class="grid grid-12 gap-2">
  <div class="col-span-4">4/12</div>
  <div class="col-span-8">8/12</div>
  <div class="col-span-6">6/12</div>
  <div class="col-span-6">6/12</div>
</div>

<!-- Positioning -->
<div class="grid grid-4 gap-2">
  <div class="col-start-2 col-span-2">
    Starts at 2nd column, takes 2
  </div>
</div>

<!-- Responsive - automatically adjusts on smaller screens -->

Theme & Dark Mode

Toggle data-theme="dark" on <html>. Persistence via localStorage recommended.

Theme Setup

JS + CSS snippet for toggle & persistence.

  • HTML attribute: <html data-theme="light">
  • JS toggles attribute and stores preference
  • Override tokens before or after import (with specificity)
πŸ’‘ Full theme example:

<html lang="en" data-theme="light">
...
<button id="themeToggle" class="btn btn-sm">Toggle theme</button>

/* CSS overrides */
:root {
  --paper-accent: #346cab;
  --paper-accent-hover: #3e79bd;
}
[data-theme="dark"] {
  --paper-bg: #1a1a1a;
  --paper-ink: #e8e4d9;
}

// JS persistence
const root = document.documentElement;
const saved = localStorage.getItem('theme');
if (saved) root.setAttribute('data-theme', saved);
document.getElementById('themeToggle').addEventListener('click', () => {
  const next = root.getAttribute('data-theme') === 'dark' ? 'light' : 'dark';
  root.setAttribute('data-theme', next);
  localStorage.setItem('theme', next);
  PaperToast.show(`Theme: ${next}`, { title: 'Theme' });
});

Override variables

:root { --paper-accent: #346cab; }

Dark test

Side Panel

This is the side panel content with authentic paper screen appearance.

  • Option 1
  • Option 2
  • Option 3