@finqu/cool
v2.0.2
Published
Build beautiful, responsive web interfaces. Fast, flexible, and effortlessly customizable.
Downloads
330
Readme
Cool UI
Build beautiful, responsive web interfaces. Fast, flexible, and effortlessly customizable.
Cool UI is a CSS + JavaScript UI toolkit built by Finqu. It provides a comprehensive set of layout primitives, components, and utility classes — all customizable at runtime through CSS custom properties.
The JavaScript layer is written in native ECMAScript (ES classes, document.querySelector, ResizeObserver, etc.). A thin jQuery compatibility wrapper is included for legacy support, but jQuery is not required to use the public API.
What's in the package
When you install @finqu/cool, you get the dist/ folder:
CSS
| File | Description |
|------|-------------|
| dist/css/cool.css | Full framework — all components, layout, and utilities |
| dist/css/cool.min.css | Minified production build |
| dist/css/cool.css.map | Source map |
| dist/css/cool.min.css.map | Minified source map |
JavaScript
| File | Description |
|------|-------------|
| dist/js/cool.bundle.js | UMD bundle — includes jQuery + PerfectScrollbar for legacy convenience |
| dist/js/cool.bundle.min.js | Minified UMD bundle |
| dist/js/cool.esm.js | ES module build (no dependencies bundled) |
| dist/js/cool.esm.min.js | Minified ES module build |
| dist/js/cool.js | UMD standalone build (no dependencies bundled) |
| dist/js/cool.min.js | Minified UMD standalone |
Bundle vs Standalone: The .bundle.js files include jQuery and PerfectScrollbar for legacy convenience. The standalone .js and .esm.js files do not include them — both are optional and can be provided externally if needed.
Installation
npm install @finqu/coolyarn add @finqu/coolpnpm add @finqu/coolQuick start
With a bundler (Webpack, Vite, Rollup, etc.)
// Import CSS (side-effect import)
import '@finqu/cool/dist/css/cool.css';
// Import JS (ES module)
import Cool from '@finqu/cool/dist/js/cool.esm.js';
// Initialize when DOM is ready
document.addEventListener('DOMContentLoaded', () => {
Cool.initialize();
});The ESM and standalone builds work without jQuery or PerfectScrollbar. Both are optional — add jQuery only if you need the legacy
$.data()plugin wrapper, and PerfectScrollbar only if you want custom scrollbars (otherwise native scrolling is used). The bundle build (cool.bundle.js) includes both for convenience.
Without a bundler (script tags)
Use the self-contained bundle that includes all dependencies:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="node_modules/@finqu/cool/dist/css/cool.min.css">
</head>
<body>
<!-- Your markup -->
<script src="node_modules/@finqu/cool/dist/js/cool.bundle.min.js"></script>
<script>
Cool.initialize();
</script>
</body>
</html>The UMD bundle exposes a global Cool object.
Usage
Cool UI uses a flat class naming convention (no BEM nesting in class names). All CSS properties are scoped under the --cool-* namespace.
Grid
A 12-column flexbox grid system with responsive breakpoints.
<div class="container">
<div class="row">
<div class="col-6">Half width</div>
<div class="col-6">Half width</div>
</div>
</div>Containers: .container (responsive max-width), .container-fluid (full width), .container-content (content-constrained width).
Responsive columns: .col-sm-*, .col-md-*, .col-lg-*, .col-xl-*
Gutters: .g-0 through .g-6, .gx-* (horizontal), .gy-* (vertical). Responsive: .g-md-3, etc.
Offsets: .offset-1 through .offset-11, with responsive variants.
Buttons
<button class="btn btn-primary">Primary</button>
<button class="btn btn-secondary">Secondary</button>
<button class="btn btn-brand">Brand</button>
<button class="btn btn-action">Action</button>
<button class="btn btn-outline-primary">Outline Primary</button>
<button class="btn btn-outline-secondary">Outline Secondary</button>
<button class="btn btn-remove">Remove</button>
<button class="btn btn-link">Link style</button>Sizes: .btn-xs, .btn-sm, .btn-lg
Full width: .btn-block
Icon button (square, equal width/height):
<button class="btn btn-icon btn-primary">
<span class="icon">✕</span>
</button>Forms
<div class="form-group">
<label>Email</label>
<input type="email" class="form-control" placeholder="[email protected]">
</div>Sizes: .form-control-sm, .form-control-lg
Floating labels:
<div class="form-label-group label-on-top">
<input type="text" class="form-control" id="name" placeholder="Name">
<label for="name">Name</label>
</div>Checkbox:
<div class="form-check">
<input type="checkbox" id="check1">
<label for="check1">
<span class="form-check-icon">
<svg viewBox="0 0 12 10"><polyline points="1.5 6 4.5 9 10.5 1"></polyline></svg>
</span>
<span class="form-check-label">Check me</span>
</label>
</div>Switch:
<div class="form-switch">
<input type="checkbox" class="form-switch-input" id="switch1">
<label class="form-switch-label" for="switch1"></label>
</div>Validation: Add .is-valid or .is-invalid to .form-control or .input-group. Pair with .valid-feedback / .invalid-feedback.
Dropdown (requires JS)
<div class="dropdown">
<button data-toggle="dropdown" class="btn btn-secondary">
Menu
</button>
<div class="dropdown-menu">
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">Separated link</a>
</div>
</div>Dialog (requires JS)
Dialogs are created programmatically. Cool.initialize() creates a Dialog singleton on document.body.
Native:
const dialog = Cool.Dialog.instances[0];
dialog.init({
title: 'Confirm action',
body: '<p>Are you sure?</p>',
size: 'sm', // '', 'sm', 'md', 'lg', 'xl', 'full'
centered: true,
callbacks: {
confirm: function(done) {
// Perform action, then close
done();
},
close: function(done) {
done();
}
},
actions: {
confirm: { content: 'Yes, confirm' },
close: { content: 'Cancel' }
}
});Legacy jQuery wrapper:
const dialog = $('body').data('plugin_coolDialog');
dialog.init({ title: 'Confirm', body: '<p>Are you sure?</p>' });Toast (requires JS)
Toasts are created programmatically. Cool.initialize() creates a Toast singleton on document.body.
Native:
const toast = Cool.Toast.instances[0];
toast.init({
content: 'Settings saved successfully',
theme: 'dark', // 'dark' or 'light'
placement: 'bottom-center',
dismiss: 3 // auto-dismiss in seconds
});Legacy jQuery wrapper:
const toast = $('body').data('plugin_coolToast');
toast.init({ content: 'Settings saved successfully' });Tooltip (requires JS)
<button data-toggle="tooltip" data-content="Helpful tip" data-placement="top">
Hover me
</button>Tooltips are auto-initialized by Cool.initialize().
Popover (requires JS)
<button data-toggle="popover"
data-title="Popover title"
data-content="Popover body content"
data-placement="bottom"
data-trigger="click">
Click me
</button>Collapse (requires JS)
<button data-toggle="collapse" data-target="#collapseContent" aria-expanded="false">
Toggle content
</button>
<div id="collapseContent" class="collapse">
<p>Collapsible content here.</p>
</div>Select (requires JS)
The custom select component replaces native selects with a searchable, styled dropdown:
<div class="select-container" data-toggle="select" data-name="category" data-type="radio">
<div class="select">
<div class="select-header">
<span class="select-title">Choose…</span>
<span class="select-icon">▾</span>
</div>
<!-- Items are rendered by JS -->
</div>
</div>Tables
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td>Item one</td>
<td><span class="badge badge-success badge-sm">Active</span></td>
</tr>
</tbody>
</table>Variants: .table-sm, .table-borderless, .table-hover, .table-striped
Badges
<span class="badge badge-primary">Default</span>
<span class="badge badge-success badge-sm">Active</span>
<span class="badge badge-outline-danger badge-xs">Urgent</span>Themes: .badge-primary, .badge-secondary, .badge-success, .badge-info, .badge-warning, .badge-danger, .badge-light, .badge-medium, .badge-dark, .badge-brand
Outline: .badge-outline-primary, .badge-outline-danger, etc.
Sizes: .badge-xs, .badge-sm
Alerts & Notifications
<div class="alert alert-info">
<div class="alert-icon">
<span class="icon">ℹ</span>
</div>
<div class="alert-content-container">
<div class="alert-content">This is an informational alert.</div>
</div>
</div>Themes: .alert-primary, .alert-secondary, .alert-success, .alert-info, .alert-warning, .alert-danger, etc.
List Group
<div class="list-group list-group-bordered list-group-hover">
<div class="list-group-item">Item one</div>
<div class="list-group-item">Item two</div>
<div class="list-group-item">Item three</div>
</div>Pagination
<ul class="pagination">
<li class="page-item disabled"><a class="page-link" href="#">‹</a></li>
<li class="page-item active"><a class="page-link" href="#">1</a></li>
<li class="page-item"><a class="page-link" href="#">2</a></li>
<li class="page-item"><a class="page-link" href="#">3</a></li>
<li class="page-item"><a class="page-link" href="#">›</a></li>
</ul>Sections
Sections are card-like content containers:
<div class="section">
<div class="section-title">
<div class="title"><p>Section title</p></div>
</div>
<div class="section-content">
<p>Section body content.</p>
</div>
</div>JavaScript initialization
Cool UI's JavaScript is written in native ECMAScript. A jQuery compatibility wrapper is included for legacy support. All public APIs are available through the global Cool object.
Full initialization
Cool.initialize({
// Optional per-component settings
popover: { /* Popover defaults */ },
dropdown: { /* Dropdown defaults */ },
tooltip: { /* Tooltip defaults */ },
select: { /* Select defaults */ },
collapse: { /* Collapse defaults */ },
sidebar: { /* Sidebar defaults */ },
toast: { /* Toast defaults */ },
dialog: { /* Dialog defaults */ }
});Cool.initialize() scans the DOM for data-toggle attributes and instantiates the matching component:
| data-toggle value | Component |
|---------------------|-----------|
| popover | Popover |
| dropdown | Dropdown |
| tooltip | Tooltip |
| select | Select |
| collapse | Collapse |
| section-tabs | SectionTabs |
Dialog and Toast are initialized on document.body and used programmatically.
Initializing dynamically added content
After adding HTML to the DOM, initialize new data-toggle elements:
Cool.initComponent('#my-new-container');
// or
Cool.initComponent(document.getElementById('my-new-container'));Re-initializing after DOM changes
Cool.refresh();Global API
All methods are available directly on the Cool global:
Cool.initialize(opts) // Initialize all components
Cool.refresh() // Re-scan DOM for new data-toggle elements
Cool.initComponent(selector) // Initialize components within a container
Cool.destroy() // Tear down all components
Cool.getSidebar() // Returns the Sidebar instance
Cool.getSection() // Returns the Section instance
Cool.observeResize(el, cb) // Watch element for size changes
Cool.unobserveResize(el) // Stop watching
Cool.addScrollListener(id, cb) // Register a scroll handler
Cool.removeScrollListener(id) // Unregister a scroll handlerAccessing component instances
Every component class has a static instances array. Singletons like Dialog and Toast
have one entry; per-element components (Dropdown, Tooltip, etc.) have one entry per element.
Native:
// Singletons (one instance on document.body)
const dialog = Cool.Dialog.instances[0];
const toast = Cool.Toast.instances[0];
// Per-element components
const dropdowns = Cool.Dropdown.instances; // all Dropdown instances
const tooltips = Cool.Tooltip.instances; // all Tooltip instances
// Sidebar & Section (dedicated getters)
const sidebar = Cool.getSidebar();
const section = Cool.getSection();Legacy jQuery wrapper:
// Per-element
const dropdown = $(element).data('plugin_coolDropdown');
dropdown.show();
dropdown.close();
dropdown.destroy();
const tooltip = $(element).data('plugin_coolTooltip');
tooltip.show();
tooltip.close();
// Singletons
const toast = $('body').data('plugin_coolToast');
const dialog = $('body').data('plugin_coolDialog');Component lifecycle callbacks
All components support lifecycle callbacks:
Cool.initialize({
dropdown: {
onInit: function() { /* Fired when initialized */ },
onShow: function() { /* Fired when shown */ },
onClose: function() { /* Fired when closed */ },
onDestroy: function() { /* Fired when destroyed */ }
}
});Utility helpers
// Observe element resize
Cool.observeResize(element, (entry) => { /* ... */ });
Cool.unobserveResize(element);
// Scroll listeners
Cool.addScrollListener('my-id', () => { /* ... */ });
Cool.removeScrollListener('my-id');Customization
Cool UI exposes hundreds of CSS custom properties on :root, all prefixed with --cool-*. Since consumers use the compiled CSS output, customization is done by overriding these properties — not by modifying Sass variables.
Overriding CSS custom properties
:root {
/* Theme colors */
--cool-theme-color-primary: #1a56db;
--cool-theme-foreground-color-primary: #ffffff;
--cool-theme-color-brand: #ff6600;
/* Typography */
--cool-font-family-base: 'Inter', sans-serif;
--cool-font-size-base: 15px;
/* Spacing */
--cool-spacer: 1rem;
/* Border radius */
--cool-border-radius: 8px;
--cool-section-border-radius: 12px;
/* Buttons */
--cool-btn-border-radius: 6px;
--cool-btn-font-weight: 600;
/* Inputs */
--cool-input-border-radius: 6px;
--cool-input-border-color: #d0d5dd;
/* Shadows */
--cool-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}Key customization categories
| Category | Example properties |
|----------|-------------------|
| Colors | --cool-theme-color-primary, --cool-theme-color-secondary, --cool-theme-color-success, --cool-theme-color-danger, --cool-theme-color-brand |
| Grey scale | --cool-color-grey-50 through --cool-color-grey-950 |
| Typography | --cool-font-family-base, --cool-font-size-base, --cool-font-weight-base, --cool-line-height-base |
| Headings | --cool-h1-font-size through --cool-h6-font-size, --cool-headings-font-family, --cool-headings-font-weight |
| Body | --cool-body-bg, --cool-body-color |
| Links | --cool-link-color, --cool-link-hover-color |
| Buttons | --cool-btn-padding-y, --cool-btn-padding-x, --cool-btn-font-size, --cool-btn-border-radius |
| Forms | --cool-input-height, --cool-input-bg, --cool-input-border-color, --cool-input-border-radius |
| Grid | --cool-grid-columns, --cool-grid-gutter-x, --cool-grid-gutter-y |
| Sections | --cool-section-border-radius, --cool-section-bg, --cool-section-border-color |
| Navbar | --cool-navbar-bg, --cool-navbar-height, --cool-navbar-color |
| Dialog | --cool-dialog-bg, --cool-dialog-width, --cool-dialog-padding-x |
| Dropdown | --cool-dropdown-bg, --cool-dropdown-border-radius, --cool-dropdown-box-shadow |
| Toast | --cool-toast-bg-dark, --cool-toast-bg-light, --cool-toast-border-radius |
| Tooltip | --cool-tooltip-bg, --cool-tooltip-color, --cool-tooltip-border-radius |
| Badge | --cool-badge-font-size, --cool-badge-border-radius, --cool-badge-padding-y |
| Shadows | --cool-box-shadow-sm, --cool-box-shadow, --cool-box-shadow-lg |
| Z-index | --cool-zindex-dropdown, --cool-zindex-dialog, --cool-zindex-toast, --cool-zindex-tooltip |
Scoped overrides
Override properties on a specific element for component-level customization:
<button class="btn btn-primary" style="--cool-btn-border-radius: 999px;">
Pill button
</button>Utility classes
Cool UI ships a full set of utility classes:
- Display:
.d-none,.d-flex,.d-block,.d-inline,.d-grid, plus responsive variants (.d-md-flex) - Flexbox:
.flex-row,.flex-column,.flex-wrap,.justify-content-*,.align-items-*,.flex-grow-*,.flex-shrink-* - Spacing:
.m-0through.m-6,.p-0through.p-6, with directional variants (.mt-*,.px-*,.mb-auto) and responsive variants - Text:
.text-left,.text-center,.text-right,.text-truncate,.text-uppercase,.text-lowercase,.text-nowrap,.font-weight-bold,.font-weight-normal - Background:
.bg-primary,.bg-secondary,.bg-success,.bg-danger, etc. - Borders:
.border,.border-0,.rounded,.rounded-circle - Sizing:
.w-100,.w-50,.h-100,.mw-100 - Position:
.position-relative,.position-absolute,.position-fixed,.position-sticky - Overflow:
.overflow-hidden,.overflow-auto,.overflow-visible - Visibility:
.visible,.invisible - Opacity:
.opacity-0,.opacity-25,.opacity-50,.opacity-75,.opacity-100 - Shadows:
.shadow-sm,.shadow,.shadow-lg,.shadow-none - Z-index:
.z-0,.z-1,.z-2,.z-3 - Cursor:
.cursor-pointer,.cursor-default,.cursor-grab - Pointer events:
.pe-none,.pe-auto - User select:
.user-select-none,.user-select-all,.user-select-auto - Screen readers:
.sr-only
CSS layers
Cool UI uses CSS @layer for cascade management:
reset, base, layout, vendor, icons, components, utilities, appThe app layer is reserved for your application styles and has the highest priority by default.
Browser support
Defined in .browserslistrc:
- Chrome ≥ 60
- Firefox ≥ 60
- Edge ≥ 79
- Safari ≥ 12
- iOS ≥ 12
- Android ≥ 6
Dependencies
Cool UI's JavaScript is written in native ECMAScript. jQuery is used only as a legacy compatibility layer for the plugin wrapper pattern.
| Dependency | Purpose | Included in bundle | Required? |
|------------|---------|-------------------|----------|
| jQuery ^3.7.1 | Legacy $.data() plugin wrapper | ✅ cool.bundle.js | Optional — only needed for the legacy jQuery wrapper |
| PerfectScrollbar ^1.5.6 | Custom scrollbars in sidebar/select | ✅ cool.bundle.js | Optional — falls back to native scrolling |
Contributing
We welcome contributions! Please read our Contributing Guide to learn about:
- Development workflow and setup
- Coding standards and conventions
- Building and testing the project
- Submitting pull requests
- Reporting bugs and requesting features
For questions or discussions, please open an issue on GitHub.
License
ISC — see LICENSE for details.
Copyright © 2026 Finqu Oy.
