Розробка бібліотеки Web Components (Shoelace)

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.

Розробка та обслуговування будь-яких видів сайтів:

Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Розробка бібліотеки Web Components (Shoelace)
Середня
~5 робочих днів
Часті питання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

Розробка бібліотеки Web Components (Shoelace)

Shoelace (тепер Web Awesome) — готова бібліотека UI-компонентів на Web Components. Близько 50 компонентів: кнопки, інпути, селекти, діалоги, тултипи, дерева, date picker. Працює без фреймворка та з будь-яким: React, Vue, Angular, Svelte.

Завдання при роботі зі Shoelace — не написати бібліотеку з нуля, а правильно налаштувати, кастомізувати під дизайн-систему та, при необхідності, розширити кастомними компонентами.

Встановлення

npm install @shoelace-style/shoelace

Або CDN (без бандлера):

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@shoelace-style/[email protected]/cdn/themes/light.css">
<script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/[email protected]/cdn/shoelace-autoloader.js"></script>

Cherry-pick імпорт (tree-shaking)

Не імпортувати всю бібліотеку — тільки потрібні компоненти:

// Реєстрація конкретних компонентів
import '@shoelace-style/shoelace/dist/components/button/button.js'
import '@shoelace-style/shoelace/dist/components/input/input.js'
import '@shoelace-style/shoelace/dist/components/dialog/dialog.js'
import '@shoelace-style/shoelace/dist/components/select/select.js'

// Налаштування шляху до іконок та ассетів
import { setBasePath } from '@shoelace-style/shoelace/dist/utilities/base-path.js'
setBasePath('/shoelace')  // копіюємо ассети в public/shoelace
// vite.config.ts — копіювання ассетів при збірці
import { viteStaticCopy } from 'vite-plugin-static-copy'

export default defineConfig({
  plugins: [
    viteStaticCopy({
      targets: [{
        src: 'node_modules/@shoelace-style/shoelace/dist/assets',
        dest: 'shoelace/assets',
      }],
    }),
  ],
})

Кастомізація через CSS Custom Properties

Shoelace побудований на дизайн-токенах. Перевизначення через CSS:

/* Глобальне перевизначення токенів */
:root {
  /* Основний колір */
  --sl-color-primary-50:  hsl(262 100% 97%);
  --sl-color-primary-100: hsl(262 95% 92%);
  --sl-color-primary-200: hsl(262 90% 85%);
  --sl-color-primary-300: hsl(262 85% 75%);
  --sl-color-primary-400: hsl(262 80% 65%);
  --sl-color-primary-500: hsl(262 75% 55%);
  --sl-color-primary-600: hsl(262 75% 45%);  /* ← основний */
  --sl-color-primary-700: hsl(262 75% 38%);
  --sl-color-primary-800: hsl(262 75% 30%);
  --sl-color-primary-900: hsl(262 75% 20%);
  --sl-color-primary-950: hsl(262 75% 12%);

  /* Типографіка */
  --sl-font-sans:   'Inter', system-ui, sans-serif;
  --sl-font-mono:   'JetBrains Mono', monospace;
  --sl-font-size-medium: 0.9375rem;  /* 15px */

  /* Радіуси */
  --sl-border-radius-small:  4px;
  --sl-border-radius-medium: 8px;
  --sl-border-radius-large:  12px;

  /* Переходи */
  --sl-transition-medium: 200ms ease;
}

CSS Parts: точкова кастомізація

Кожний Shoelace-компонент експортує ::part() для зовнішної стилізації:

/* Кастомізація кнопки */
sl-button::part(base) {
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  font-size: 13px;
}

sl-button[variant="primary"]::part(base) {
  background: linear-gradient(135deg, #7000ff, #b600ff);
  border: none;
}

sl-button[variant="primary"]::part(base):hover {
  background: linear-gradient(135deg, #5500cc, #9400cc);
}

/* Інпут */
sl-input::part(base) {
  border-radius: 10px;
  border-width: 1.5px;
}

sl-input::part(input) {
  font-size: 15px;
}

/* Діалог */
sl-dialog::part(panel) {
  border-radius: 20px;
  box-shadow: 0 25px 60px rgba(0,0,0,0.3);
}

sl-dialog::part(overlay) {
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(4px);
}

Інтеграція з React

npm install @shoelace-style/shoelace
// src/shoelace-setup.ts — запустити один раз
import { setBasePath } from '@shoelace-style/shoelace/dist/utilities/base-path.js'
import '@shoelace-style/shoelace/dist/components/button/button.js'
import '@shoelace-style/shoelace/dist/components/input/input.js'
import '@shoelace-style/shoelace/dist/components/dialog/dialog.js'
import '@shoelace-style/shoelace/dist/themes/light.css'

setBasePath('/shoelace')
// Типи для TypeScript + JSX
// src/types/shoelace.d.ts
import type { SlButton, SlInput, SlDialog } from '@shoelace-style/shoelace'

declare module 'react' {
  namespace JSX {
    interface IntrinsicElements {
      'sl-button': React.DetailedHTMLProps<
        React.HTMLAttributes<SlButton> & {
          variant?: 'default' | 'primary' | 'success' | 'neutral' | 'warning' | 'danger' | 'text'
          size?: 'small' | 'medium' | 'large'
          disabled?: boolean
          loading?: boolean
          outline?: boolean
          pill?: boolean
          circle?: boolean
          type?: 'button' | 'submit' | 'reset'
          href?: string
          target?: string
        },
        SlButton
      >
      'sl-input': React.DetailedHTMLProps<
        React.HTMLAttributes<SlInput> & {
          type?: string
          label?: string
          placeholder?: string
          value?: string
          required?: boolean
          disabled?: boolean
          readonly?: boolean
          'help-text'?: string
          'error-message'?: string
          clearable?: boolean
          'password-toggle'?: boolean
        },
        SlInput
      >
      'sl-dialog': React.DetailedHTMLProps<
        React.HTMLAttributes<SlDialog> & {
          label?: string
          open?: boolean
          'no-header'?: boolean
        },
        SlDialog
      >
    }
  }
}
import { useRef } from 'react'
import type SlDialog from '@shoelace-style/shoelace/dist/components/dialog/dialog.js'
import '../shoelace-setup'

export function ContactModal() {
  const dialogRef = useRef<SlDialog>(null)

  const openDialog = () => dialogRef.current?.show()
  const closeDialog = () => dialogRef.current?.hide()

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault()
    // ...
    closeDialog()
  }

  return (
    <>
      <sl-button variant="primary" onClick={openDialog}>
        Написати нам
      </sl-button>

      <sl-dialog ref={dialogRef} label="Контактна форма">
        <form onSubmit={handleSubmit}>
          <sl-input
            label="Ім'я"
            required
            placeholder="Іван Іванов"
            style={{ marginBottom: '16px' }}
          />
          <sl-input
            label="Email"
            type="email"
            required
            placeholder="[email protected]"
            style={{ marginBottom: '16px' }}
          />
          <sl-textarea
            label="Повідомлення"
            rows={4}
            required
          />
        </form>

        <sl-button slot="footer" variant="default" onClick={closeDialog}>
          Скасувати
        </sl-button>
        <sl-button slot="footer" variant="primary" type="submit">
          Відправити
        </sl-button>
      </sl-dialog>
    </>
  )
}

Темна тема

Shoelace підтримує dark/light через CSS-клас на <html>:

<!-- Light -->
<html class="sl-theme-light">

<!-- Dark -->
<html class="sl-theme-dark">
// Переключення теми
function toggleTheme() {
  const html = document.documentElement
  const isDark = html.classList.contains('sl-theme-dark')
  html.classList.toggle('sl-theme-dark', !isDark)
  html.classList.toggle('sl-theme-light', isDark)
  localStorage.setItem('theme', isDark ? 'light' : 'dark')
}

// Ініціалізація за prefers-color-scheme
const savedTheme = localStorage.getItem('theme')
  || (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')
document.documentElement.classList.add(`sl-theme-${savedTheme}`)

Створення кастомних компонентів у стилі Shoelace

Якщо бібліотека розширюється власними компонентами, наслідуємо від ShoelaceElement:

import ShoelaceElement from '@shoelace-style/shoelace/dist/internal/shoelace-element.js'
import { customElement, property } from 'lit/decorators.js'
import { html, css } from 'lit'

@customElement('app-stat-card')
export class AppStatCard extends ShoelaceElement {
  static styles = css`
    :host { display: block; }
    /* ... */
  `

  @property() label = ''
  @property({ type: Number }) value = 0
  @property() unit = ''

  render() {
    return html`
      <div class="stat-card">
        <div class="stat-value">${this.value}<span>${this.unit}</span></div>
        <div class="stat-label">${this.label}</div>
      </div>
    `
  }
}

Терміни

Налаштування Shoelace + кастомізація під дизайн-систему + React-інтеграція — 2–4 дні. Додатково кастомні компоненти на базі Shoelace/Lit + dark theme + документація — ще 1–2 тижні.