Working with the ss-icon Web Component and ss-loader
This skill covers the two JavaScript components that render icons.
Location: src/ss-icon.js
<ss-icon icon="check"></ss-icon>
<ss-icon icon="arrow-left" thickness="1.5"></ss-icon>
| Attribute | Type | Default | Description |
|---|---|---|---|
icon |
string | - | Icon slug from icons.json |
thickness |
number | 2 | Stroke width of the icon |
class SSIcon extends HTMLElement {
// Watch for attribute changes
static get observedAttributes() {
return ["icon", "thickness"];
}
constructor() {
super();
this.attachShadow({ mode: "open" });
}
// Re-render when attributes change
attributeChangedCallback(name, oldValue, newValue) {
if (name === "icon" || name === "thickness") {
this.render();
}
}
render() {
const iconName = this.getAttribute("icon");
const iconSvg = icons[iconName];
// Inject SVG with custom thickness into shadow DOM
}
}
customElements.define("ss-icon", SSIcon);
The component inherits color from parent:
.my-button {
color: blue;
}
.my-button ss-icon {
/* Icon will be blue */
}
Override size:
ss-icon {
font-size: 24px; /* Icons scale with font-size */
}
Location: src/ss-loader.js
<i class="ss ss-check"></i>
<i class="ss ss-arrow-left"></i>
i.ss elementsss-data-ss-loaded="true" to prevent reprocessingfunction replaceIcons() {
const elements = document.querySelectorAll("i.ss");
elements.forEach((el) => {
if (el.dataset.ssLoaded) return; // Skip already processed
const iconClass = classes.find(c => c.startsWith("ss-"));
const iconName = iconClass.replace("ss-", "");
const iconSvg = icons[iconName];
if (iconSvg) {
el.innerHTML = iconSvg;
el.dataset.ssLoaded = "true";
}
});
}
// Watch for dynamically added icons
const observer = new MutationObserver((mutations) => {
// Check for added nodes or class changes
if (shouldUpdate) replaceIcons();
});
observer.observe(document.body, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ["class"]
});
.ss {
display: inline-block;
width: 1em;
height: 1em;
vertical-align: middle;
}
/* Custom styling */
.ss-check {
color: green;
font-size: 2rem;
}
For environments without JavaScript, use the CSS-only approach:
<link rel="stylesheet" href="senangstart.min.css">
<i class="ss ss-check"></i>
The CSS uses mask-image with data URIs - no JavaScript required.
observedAttributes arrayrender() methodtests/ss-icon.test.jscolor attributestatic get observedAttributes() {
return ["icon", "thickness", "color"];
}
render() {
const color = this.getAttribute("color") || "currentColor";
this.shadowRoot.innerHTML = `
<style>
:host { color: ${color}; }
/* ... */
</style>
${finalSvg}
`;
}
render() {
const animate = this.hasAttribute("animate");
this.shadowRoot.innerHTML = `
<style>
${animate ? `
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
svg { animation: spin 1s linear infinite; }
` : ""}
</style>
${finalSvg}
`;
}