@finqu/cool
v1.3.0
Published
Build beautiful, responsive web interfaces. Fast, flexible, and effortlessly customizable.
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 with all dependencies (jQuery, PerfectScrollbar) included |
| dist/js/cool.bundle.min.js | Minified UMD bundle |
| dist/js/cool.esm.js | ES module build (external jQuery) |
| dist/js/cool.esm.min.js | Minified ES module build |
| dist/js/cool.js | UMD standalone build (external jQuery) |
| dist/js/cool.min.js | Minified UMD standalone |
Bundle vs Standalone: The .bundle.js files include jQuery and PerfectScrollbar for legacy compatibility. The standalone .js and .esm.js files keep these as external dependencies.
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 build expects jQuery and PerfectScrollbar as external dependencies. The bundle build (
cool.bundle.js) includes them automatically.
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 for standalone/ESM |
|------------|---------|-------------------|-----------------------------|
| jQuery ^3.7.1 | Legacy plugin wrapper | ✅ cool.bundle.js | Must be provided externally |
| PerfectScrollbar ^1.5.6 | Custom scrollbars | ✅ cool.bundle.js | Must be provided externally |
License
ISC — see LICENSE for details.
Copyright © 2026 Finqu Oy.
