Storage & State
JavaScript components for cookie consent, local storage, and UI state management.
Cookie Consent Manager
GDPR-compliant cookie consent with category control.
◉ We use cookies
We use cookies to enhance your browsing experience, serve personalized content, and analyze our traffic. By clicking "Accept All", you consent to our use of cookies.
Cookie Preferences
<!-- Cookie consent banner -->
<div
data-ss="cookie-consent"
data-ss-cookie-position="bottom"
data-ss-cookie-privacy-url="/privacy"
style="
position: relative;
padding: 24px;
background: white;
border-radius: 16px;
box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.1);
"
>
<div
style="
display: flex;
gap: 24px;
align-items: flex-start;
flex-wrap: wrap;
"
>
<div style="flex: 1; min-width: 300px">
<h4 style="margin: 0 0 8px">◉ We use cookies</h4>
<p style="margin: 0; font-size: 14px; opacity: 0.8">
We use cookies to enhance your browsing experience,
serve personalized content, and analyze our traffic. By
clicking "Accept All", you consent to our use of
cookies.
</p>
</div>
<div style="display: flex; gap: 12px; flex-wrap: wrap">
<button
style="
padding: 12px 24px;
background: var(--color_fill_secondary);
border: none;
border-radius: 8px;
cursor: pointer;
"
>
Customize
</button>
<button
style="
padding: 12px 24px;
background: var(--color_fill_primary);
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
"
>
Accept All
</button>
</div>
</div>
</div>
<!-- Cookie preferences modal -->
<div
style="
margin-top: 24px;
padding: 24px;
background: white;
border-radius: 16px;
border: 1px solid var(--color_line_secondary);
max-width: 500px;
"
>
<h4 style="margin: 0 0 20px">Cookie Preferences</h4>
<div style="display: flex; flex-direction: column; gap: 16px">
<!-- Essential cookies -->
<div
style="
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 16px;
border-bottom: 1px solid var(--color_line_secondary);
"
>
<div>
<strong style="display: block">
Essential Cookies
</strong>
<span style="font-size: 13px; opacity: 0.7">
Required for the website to function
</span>
</div>
<input
type="checkbox"
checked
disabled
style="width: 44px; height: 24px"
/>
</div>
<!-- Analytics cookies -->
<div
style="
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 16px;
border-bottom: 1px solid var(--color_line_secondary);
"
>
<div>
<strong style="display: block">
Analytics Cookies
</strong>
<span style="font-size: 13px; opacity: 0.7">
Help us improve our website
</span>
</div>
<input
type="checkbox"
data-ss-cookie-category="analytics"
style="width: 44px; height: 24px"
/>
</div>
<!-- Marketing cookies -->
<div
style="
display: flex;
justify-content: space-between;
align-items: center;
"
>
<div>
<strong style="display: block">
Marketing Cookies
</strong>
<span style="font-size: 13px; opacity: 0.7">
Used for targeted advertising
</span>
</div>
<input
type="checkbox"
data-ss-cookie-category="marketing"
style="width: 44px; height: 24px"
/>
</div>
</div>
<div style="display: flex; gap: 12px; margin-top: 24px">
<button
style="
flex: 1;
padding: 12px;
background: var(--color_fill_secondary);
border: none;
border-radius: 8px;
cursor: pointer;
"
>
Reject All
</button>
<button
style="
flex: 1;
padding: 12px;
background: var(--color_fill_primary);
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
"
>
Save Preferences
</button>
</div>
</div>
Conditional Script Loading
Block scripts until consent is given for their category.
<!-- Scripts blocked until consent -->
<script data-ss-cookie-category="analytics" type="text/plain">
// Google Analytics - only runs if analytics cookies accepted
gtag('config', 'GA_MEASUREMENT_ID');
</script>
<script data-ss-cookie-category="marketing" type="text/plain">
// Facebook Pixel - only runs if marketing cookies accepted
fbq('init', 'PIXEL_ID');
fbq('track', 'PageView');
</script>
<!-- Essential scripts always run -->
<script>
// Core functionality - always executes
initApp();
</script>
Local Storage Manager
Wrapper for localStorage with error handling and namespacing.
Local Storage Demo
Stored Data:
| Key | Value | Actions |
|---|---|---|
| theme | "dark" | |
| user | {"name": "John"} |
<!-- Storage demo UI -->
<div
style="
max-width: 500px;
padding: 24px;
background: var(--color_fill_secondary);
border-radius: 12px;
"
>
<h4 style="margin: 0 0 16px">Local Storage Demo</h4>
<div style="display: flex; gap: 12px; margin-bottom: 16px">
<input
type="text"
id="storageKey"
placeholder="Key"
style="
flex: 1;
padding: 10px 14px;
border: 1px solid var(--color_line_secondary);
border-radius: 6px;
"
/>
<input
type="text"
id="storageValue"
placeholder="Value"
style="
flex: 1;
padding: 10px 14px;
border: 1px solid var(--color_line_secondary);
border-radius: 6px;
"
/>
</div>
<div style="display: flex; gap: 8px; flex-wrap: wrap">
<button
onclick="setStorage()"
style="
padding: 10px 16px;
background: var(--color_fill_primary);
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
"
>
Set
</button>
<button
onclick="getStorage()"
style="
padding: 10px 16px;
background: white;
border: 1px solid var(--color_line_secondary);
border-radius: 6px;
cursor: pointer;
"
>
Get
</button>
<button
onclick="removeStorage()"
style="
padding: 10px 16px;
background: white;
border: 1px solid var(--color_line_secondary);
border-radius: 6px;
cursor: pointer;
"
>
Remove
</button>
<button
onclick="clearStorage()"
style="
padding: 10px 16px;
background: var(--color_state_error);
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
"
>
Clear All
</button>
</div>
<div
id="storageOutput"
style="
margin-top: 16px;
padding: 12px;
background: white;
border-radius: 6px;
font-family: monospace;
font-size: 13px;
min-height: 40px;
"
></div>
</div>
<!-- Stored data display -->
<div style="margin-top: 24px; max-width: 500px">
<h5 style="margin: 0 0 12px; opacity: 0.7">Stored Data:</h5>
<table style="width: 100%; border-collapse: collapse">
<thead>
<tr style="background: var(--color_fill_secondary)">
<th
style="
padding: 10px 12px;
text-align: left;
border-bottom: 1px solid
var(--color_line_secondary);
"
>
Key
</th>
<th
style="
padding: 10px 12px;
text-align: left;
border-bottom: 1px solid
var(--color_line_secondary);
"
>
Value
</th>
<th
style="
padding: 10px 12px;
text-align: center;
border-bottom: 1px solid
var(--color_line_secondary);
"
>
Actions
</th>
</tr>
</thead>
<tbody>
<tr>
<td
style="
padding: 10px 12px;
border-bottom: 1px solid
var(--color_line_secondary);
font-family: monospace;
"
>
theme
</td>
<td
style="
padding: 10px 12px;
border-bottom: 1px solid
var(--color_line_secondary);
font-family: monospace;
"
>
"dark"
</td>
<td
style="
padding: 10px 12px;
text-align: center;
border-bottom: 1px solid
var(--color_line_secondary);
"
>
<button
style="
padding: 4px 8px;
background: none;
border: none;
cursor: pointer;
"
>
␡
</button>
</td>
</tr>
<tr>
<td
style="
padding: 10px 12px;
border-bottom: 1px solid
var(--color_line_secondary);
font-family: monospace;
"
>
user
</td>
<td
style="
padding: 10px 12px;
border-bottom: 1px solid
var(--color_line_secondary);
font-family: monospace;
"
>
{"name": "John"}
</td>
<td
style="
padding: 10px 12px;
text-align: center;
border-bottom: 1px solid
var(--color_line_secondary);
"
>
<button
style="
padding: 4px 8px;
background: none;
border: none;
cursor: pointer;
"
>
␡
</button>
</td>
</tr>
</tbody>
</table>
</div>
State Manager
Manages UI element states via class toggling.
The sidebar can be toggled with state management.
Theme State
<!-- State toggle buttons -->
<div style="display: flex; gap: 12px; margin-bottom: 24px">
<button
data-ss="state-toggle"
data-ss-state-target="#sidebar"
data-ss-state-class="is-open"
style="
padding: 10px 20px;
background: var(--color_fill_primary);
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
"
>
Toggle Sidebar
</button>
<button
data-ss="state-toggle"
data-ss-state-target="#menu"
data-ss-state-class="is-expanded"
style="
padding: 10px 20px;
background: var(--color_fill_secondary);
border: none;
border-radius: 6px;
cursor: pointer;
"
>
Toggle Menu
</button>
</div>
<!-- Elements with state classes -->
<div
style="display: grid; grid-template-columns: 200px 1fr; gap: 16px"
>
<div
id="sidebar"
class="is-open"
style="
padding: 16px;
background: var(--color_fill_secondary);
border-radius: 8px;
transition:
transform 0.3s,
opacity 0.3s;
"
>
<strong style="display: block; margin-bottom: 8px">
Sidebar
</strong>
<p style="font-size: 14px; opacity: 0.7; margin: 0">
State: Open
</p>
</div>
<div
style="
padding: 16px;
background: var(--color_fill_secondary);
border-radius: 8px;
"
>
<strong>Main Content</strong>
<p style="font-size: 14px; opacity: 0.7; margin: 8px 0 0">
The sidebar can be toggled with state management.
</p>
</div>
</div>
<!-- Multi-state example -->
<div
style="
margin-top: 24px;
padding: 20px;
background: var(--color_fill_secondary);
border-radius: 12px;
"
>
<h5 style="margin: 0 0 16px">Theme State</h5>
<div style="display: flex; gap: 8px">
<button
data-ss="state-toggle"
data-ss-state-target="body"
data-ss-state-class="ss-c-theme-light"
data-ss-state-remove="theme-dark theme-auto"
style="
padding: 10px 16px;
background: white;
border: 1px solid var(--color_line_secondary);
border-radius: 6px;
cursor: pointer;
"
>
☀ Light
</button>
<button
data-ss="state-toggle"
data-ss-state-target="body"
data-ss-state-class="ss-c-theme-dark"
data-ss-state-remove="theme-light theme-auto"
style="
padding: 10px 16px;
background: #1a1a2e;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
"
>
☾ Dark
</button>
<button
data-ss="state-toggle"
data-ss-state-target="body"
data-ss-state-class="ss-c-theme-auto"
data-ss-state-remove="theme-light theme-dark"
style="
padding: 10px 16px;
background: var(--color_fill_secondary);
border: 1px solid var(--color_line_secondary);
border-radius: 6px;
cursor: pointer;
"
>
↻ Auto
</button>
</div>
</div>
Theme Toggle
Dark/light theme switching with localStorage persistence.
Current theme: light
<!-- Theme toggle checkbox -->
<div
style="
display: flex;
align-items: center;
gap: 12px;
padding: 20px;
background: var(--color_fill_secondary);
border-radius: 12px;
max-width: 300px;
"
>
<span>☀</span>
<label
style="
position: relative;
display: inline-block;
width: 52px;
height: 28px;
"
>
<input
type="checkbox"
id="themeToggle"
data-theme-toggle
style="opacity: 0; width: 0; height: 0"
/>
<span
style="
position: absolute;
cursor: pointer;
inset: 0;
background: var(--color_line_secondary);
border-radius: 14px;
transition: background 0.3s;
"
>
<span
style="
position: absolute;
content: "";
height: 22px;
width: 22px;
left: 3px;
bottom: 3px;
background: white;
border-radius: 50%;
transition: transform 0.3s;
"
></span>
</span>
</label>
<span>☾</span>
</div>
<!-- Theme toggle button -->
<button
data-theme-toggle
style="
margin-top: 16px;
padding: 12px 24px;
background: var(--color_fill_primary);
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
display: flex;
align-items: center;
gap: 8px;
"
>
<span id="themeIcon">☾</span>
<span>Toggle Theme</span>
</button>
<!-- Theme indicator -->
<div
style="
margin-top: 24px;
padding: 16px;
background: var(--color_fill_secondary);
border-radius: 8px;
"
>
<p style="margin: 0; font-family: monospace">
Current theme:
<strong id="currentTheme">light</strong>
</p>
</div>
JavaScript API
Programmatic control of storage and state components.
<script>
// CookieConsentManager
import { CookieConsentManager } from "stylescape";
const cookieConsent = new CookieConsentManager({
position: "bottom",
privacyUrl: "/privacy",
categories: ["essential", "analytics", "marketing"],
onAccept: (categories) => {
console.log("Accepted categories:", categories);
if (categories.includes("analytics")) {
loadAnalytics();
}
},
onReject: () => {
console.log("Cookies rejected");
},
});
cookieConsent.show();
cookieConsent.hide();
cookieConsent.acceptAll();
cookieConsent.rejectAll();
cookieConsent.acceptCategory("analytics");
cookieConsent.hasConsent("marketing"); // Check if category accepted
// LocalStorageManager
import { LocalStorageManager } from "stylescape";
const storage = LocalStorageManager.getInstance();
// Basic operations
storage.setValue("key", "value");
storage.getValue("key");
storage.removeValue("key");
storage.clearStorage();
// With expiration
storage.setValue("session", data, { expires: 3600 }); // 1 hour
// With namespace
const userStorage = LocalStorageManager.getInstance("user");
userStorage.setValue("preferences", { theme: "dark" });
// JSON auto-serialization
storage.setValue("user", { name: "John", age: 30 });
const user = storage.getValue("user"); // Returns object
// StateManager
import { StateManager } from "stylescape";
const stateManager = new StateManager({
persist: true,
storageKey: "app-state",
});
stateManager.addClass("#element", "is-active");
stateManager.removeClass("#element", "is-active");
stateManager.toggleClass("#element", "is-open");
stateManager.hasClass("#element", "is-active");
// ThemeToggle
import { ThemeToggle } from "stylescape";
ThemeToggle.init({
storageKey: "theme-preference",
defaultTheme: "light",
onChange: (theme) => {
console.log("Theme changed to:", theme);
},
});
ThemeToggle.setTheme("dark");
ThemeToggle.getTheme();
ThemeToggle.toggle();
</script>