@zavvla/shared-socials
v0.1.3
Published
Lightweight social sharing widget with analytics support
Maintainers
Readme
@zavvla/shared-socials — Виджет «Поделиться социальной сетью»
Лёгкий виджет шаринга для социальных сетей. Zero-dependency TypeScript библиотека.
- Zero dependencies — чистый TypeScript, без сторонних зависимостей
- Shadow DOM — изоляция стилей по умолчанию, CSS инжектируется автоматически
- 20 встроенных сетей — VK, Telegram, WhatsApp, Twitter/X, Facebook и другие
- Гибкая инициализация — через
data-атрибуты или JS API - Аналитика — Яндекс.Метрика, Google Analytics 4, кастомные адаптеры
- Кастомные сети — добавляйте любые соц. сети
Установка
npm install @zavvla/shared-socialsБыстрый старт
CDN (без сборщика)
<div data-share-widget data-networks="vk,telegram,whatsapp"></div>
<script src="https://unpkg.com/@zavvla/shared-socials/dist/shared-socials.global.js"></script>CSS подключать не нужно — стили инжектируются автоматически через Shadow DOM.
ESM / TypeScript
import { ShareWidget } from '@zavvla/shared-socials'
new ShareWidget({
target: '#share',
networks: ['vk', 'telegram', 'whatsapp'],
url: 'https://example.com',
title: 'Заголовок страницы',
})Data-атрибуты
| Атрибут | Тип | По умолчанию | Описание |
|---------------------|---------------------------------|------------------|-----------------------------------|
| data-share-widget | — | — | Маркер для авто-инициализации |
| data-networks | vk,telegram,... | vk,telegram | Список сетей через запятую |
| data-url | string | текущий URL | URL для шаринга |
| data-title | string | document.title | Заголовок |
| data-description | string | og:description | Описание |
| data-image | string | og:image | URL изображения |
| data-mode | icon | text | icon-text | icon-text | Режим отображения кнопок |
| data-icon-mode | svg | css | svg | Способ рендера иконок |
| data-open-mode | blank | popup | blank | Открывать в новой вкладке / popup |
| data-shadow | boolean (наличие атрибута) | включён | Shadow DOM изоляция |
JS API
Конфигурация
new ShareWidget({
target: '#share', // string | HTMLElement, по умолчанию document.body
networks: ['vk', 'telegram'], // список сетей (по умолчанию ['vk', 'telegram'])
url: 'https://example.com', // по умолчанию window.location.href
title: 'Заголовок', // по умолчанию document.title
description: 'Описание', // по умолчанию og:description meta
image: 'https://example.com/og.jpg', // по умолчанию og:image meta
mode: 'icon-text', // 'icon' | 'text' | 'icon-text'
iconMode: 'svg', // 'svg' | 'css'
openMode: 'blank', // 'blank' | 'popup'
popup: { width: 700, height: 520 },
shadow: true, // Shadow DOM (по умолчанию: true)
injectStyles: true, // авто-инжект CSS (по умолчанию: true)
classes: {
container: 'my-share',
button: 'my-share__btn',
buttonNetworkPrefix: 'my-share__btn--',
icon: 'my-share__icon',
label: 'my-share__label',
},
metrics: {
adapters: [new YandexMetrikaAdapter({ counterId: 12345 })],
onEvent: (event) => console.log(event),
},
})Методы
widget.update({ mode: 'icon', networks: ['vk', 'telegram'] }) // обновить конфиг
widget.destroy() // удалить из DOMСобытия
widget
.on('click', ({ network, url }) => console.log('клик', network))
.on('open', ({ network, url }) => console.log('открыто', network))
.on('cancel', ({ network, url }) => console.log('popup закрыт'))
.on('render', ({ url }) => console.log('виджет отрендерен'))
.on('error', ({ network, message }) => console.error(message))| Событие | Payload | Когда |
|----------|-----------------------------|----------------------------------------------|
| click | { network, url } | Пользователь кликнул кнопку |
| open | { network, url } | Окно/вкладка шаринга открылась |
| cancel | { network, url } | Popup закрыт без шаринга (openMode: popup) |
| render | { url } | Виджет смонтирован в DOM |
| error | { network, url, message } | Ошибка при открытии окна |
Встроенные сети
| ID | Название | ID | Название |
|--------------|---------------|--------------|-------------|
| vk | ВКонтакте | linkedin | LinkedIn |
| ok | Одноклассники | pinterest | Pinterest |
| telegram | Telegram | reddit | Reddit |
| whatsapp | WhatsApp | tumblr | Tumblr |
| twitter | Twitter / X | skype | Skype |
| viber | Viber | line | Line |
| facebook | Facebook | bluesky | Bluesky |
| hackernews | Hacker News | pocket | Pocket |
| weibo | Weibo | xing | Xing |
| mastodon | Mastodon | email | Email |
Shadow DOM и стили
// Shadow DOM + авто-стили (по умолчанию)
new ShareWidget({ target: '#share' })
// Shadow DOM, стили пишешь сам через ::part()
new ShareWidget({ target: '#share', injectStyles: false })
// Без Shadow DOM, авто-стили в <head>
new ShareWidget({ target: '#share', shadow: false, injectStyles: true })
// Без Shadow DOM, CSS вручную через <link>
new ShareWidget({ target: '#share', shadow: false, injectStyles: false })Стилизация через CSS Parts API (при shadow: true)
#share::part(container) { display: flex; gap: 8px; }
#share::part(button) { border-radius: 8px; padding: 8px 12px; }
#share::part(button-vk) { background: #0077ff; color: #fff; }
#share::part(icon) { width: 20px; height: 20px; }
#share::part(label) { font-size: 14px; }CSS-классы по умолчанию (при shadow: false)
| Элемент | Класс |
|-------------|---------------------------|
| Контейнер | share-box |
| Кнопка | share-box__button |
| Кнопка сети | share-box__button--{id} |
| Иконка | share-box__icon |
| Текст | share-box__label |
Кастомные сети
import { ShareWidget } from '@zavvla/shared-socials'
import type { NetworkDefinition } from '@zavvla/shared-socials'
const livejournalNetwork: NetworkDefinition = {
id: 'livejournal',
label: 'LiveJournal',
defaultIcon: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">...</svg>`,
buildUrl({ url, title }) {
return `https://www.livejournal.com/update.bml?subject=${encodeURIComponent(title ?? '')}&prop_url=${encodeURIComponent(url)}`
},
}
new ShareWidget({
networks: ['vk', 'telegram', 'livejournal'],
customNetworks: [livejournalNetwork],
})Аналитика
Яндекс.Метрика
import { ShareWidget, YandexMetrikaAdapter } from '@zavvla/shared-socials'
new ShareWidget({
metrics: {
adapters: [new YandexMetrikaAdapter({ counterId: 12345678 })],
},
})Google Analytics 4
import { GoogleAnalyticsAdapter } from '@zavvla/shared-socials/analytics'
new ShareWidget({
metrics: {
adapters: [new GoogleAnalyticsAdapter({ measurementId: 'G-XXXXXXXXXX' })],
},
})Кастомный адаптер
import type { MetricsAdapter, ShareMetricEvent } from '@zavvla/shared-socials'
class MyAdapter implements MetricsAdapter {
readonly name = 'MyAnalytics'
readonly docsUrl = 'https://my-analytics.example.com'
isAvailable() {
return typeof window.myAnalytics !== 'undefined'
}
track(event: ShareMetricEvent) {
window.myAnalytics.send(event.type, { network: event.network, url: event.url })
}
}
new ShareWidget({ metrics: { adapters: [new MyAdapter()] } })Лицензия
MIT © zavvla
English
Lightweight social sharing widget. Zero-dependency TypeScript library.
- Zero dependencies — pure TypeScript, no third-party dependencies
- Shadow DOM — style isolation by default, CSS injected automatically
- 20 built-in networks — VK, Telegram, WhatsApp, Twitter/X, Facebook and more
- Flexible initialization — via
dataattributes or JS API - Analytics — Yandex.Metrika, Google Analytics 4, custom adapters
- Custom networks — add any social network
Installation
npm install @zavvla/shared-socialsQuick Start
CDN (no bundler)
<div data-share-widget data-networks="vk,telegram,whatsapp"></div>
<script src="https://unpkg.com/@zavvla/shared-socials/dist/shared-socials.global.js"></script>No need to include CSS — styles are injected automatically via Shadow DOM.
ESM / TypeScript
import { ShareWidget } from '@zavvla/shared-socials'
new ShareWidget({
target: '#share',
networks: ['vk', 'telegram', 'whatsapp'],
url: 'https://example.com',
title: 'Page title',
})Data Attributes
| Attribute | Type | Default | Description |
|---------------------|---------------------------------|------------------|-----------------------------------|
| data-share-widget | — | — | Marker for auto-initialization |
| data-networks | vk,telegram,... | vk,telegram | Comma-separated network list |
| data-url | string | current URL | URL to share |
| data-title | string | document.title | Title |
| data-description | string | og:description | Description |
| data-image | string | og:image | Image URL |
| data-mode | icon | text | icon-text | icon-text | Button display mode |
| data-icon-mode | svg | css | svg | Icon render method |
| data-open-mode | blank | popup | blank | Open in new tab or popup |
| data-shadow | boolean (attribute presence) | enabled | Shadow DOM isolation |
JS API
Configuration
new ShareWidget({
target: '#share', // string | HTMLElement, default: document.body
networks: ['vk', 'telegram'], // network list (default: ['vk', 'telegram'])
url: 'https://example.com', // default: window.location.href
title: 'Title', // default: document.title
description: 'Description', // default: og:description meta
image: 'https://example.com/og.jpg', // default: og:image meta
mode: 'icon-text', // 'icon' | 'text' | 'icon-text'
iconMode: 'svg', // 'svg' | 'css'
openMode: 'blank', // 'blank' | 'popup'
popup: { width: 700, height: 520 },
shadow: true, // Shadow DOM (default: true)
injectStyles: true, // auto-inject CSS (default: true)
classes: {
container: 'my-share',
button: 'my-share__btn',
buttonNetworkPrefix: 'my-share__btn--',
icon: 'my-share__icon',
label: 'my-share__label',
},
metrics: {
adapters: [new YandexMetrikaAdapter({ counterId: 12345 })],
onEvent: (event) => console.log(event),
},
})Methods
widget.update({ mode: 'icon', networks: ['vk', 'telegram'] }) // update config
widget.destroy() // remove from DOMEvents
widget
.on('click', ({ network, url }) => console.log('clicked', network))
.on('open', ({ network, url }) => console.log('opened', network))
.on('cancel', ({ network, url }) => console.log('popup closed'))
.on('render', ({ url }) => console.log('widget rendered'))
.on('error', ({ network, message }) => console.error(message))| Event | Payload | When |
|----------|-----------------------------|----------------------------------------------|
| click | { network, url } | User clicked a button |
| open | { network, url } | Share window/tab opened |
| cancel | { network, url } | Popup closed without sharing (openMode: popup) |
| render | { url } | Widget mounted to DOM |
| error | { network, url, message } | Error opening window |
Built-in Networks
| ID | Name | ID | Name |
|--------------|---------------|--------------|-------------|
| vk | VKontakte | linkedin | LinkedIn |
| ok | Odnoklassniki | pinterest | Pinterest |
| telegram | Telegram | reddit | Reddit |
| whatsapp | WhatsApp | tumblr | Tumblr |
| twitter | Twitter / X | skype | Skype |
| viber | Viber | line | Line |
| facebook | Facebook | bluesky | Bluesky |
| hackernews | Hacker News | pocket | Pocket |
| weibo | Weibo | xing | Xing |
| mastodon | Mastodon | email | Email |
Shadow DOM & Styles
// Shadow DOM + auto styles (default)
new ShareWidget({ target: '#share' })
// Shadow DOM, custom styles via ::part()
new ShareWidget({ target: '#share', injectStyles: false })
// No Shadow DOM, auto styles in <head>
new ShareWidget({ target: '#share', shadow: false, injectStyles: true })
// No Shadow DOM, manual CSS via <link>
new ShareWidget({ target: '#share', shadow: false, injectStyles: false })CSS Parts API (when shadow: true)
#share::part(container) { display: flex; gap: 8px; }
#share::part(button) { border-radius: 8px; padding: 8px 12px; }
#share::part(button-vk) { background: #0077ff; color: #fff; }
#share::part(icon) { width: 20px; height: 20px; }
#share::part(label) { font-size: 14px; }Default CSS Classes (when shadow: false)
| Element | Class |
|-----------|---------------------------|
| Container | share-box |
| Button | share-box__button |
| Network | share-box__button--{id} |
| Icon | share-box__icon |
| Label | share-box__label |
Custom Networks
import { ShareWidget } from '@zavvla/shared-socials'
import type { NetworkDefinition } from '@zavvla/shared-socials'
const livejournalNetwork: NetworkDefinition = {
id: 'livejournal',
label: 'LiveJournal',
defaultIcon: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">...</svg>`,
buildUrl({ url, title }) {
return `https://www.livejournal.com/update.bml?subject=${encodeURIComponent(title ?? '')}&prop_url=${encodeURIComponent(url)}`
},
}
new ShareWidget({
networks: ['vk', 'telegram', 'livejournal'],
customNetworks: [livejournalNetwork],
})Analytics
Yandex.Metrika
import { ShareWidget, YandexMetrikaAdapter } from '@zavvla/shared-socials'
new ShareWidget({
metrics: {
adapters: [new YandexMetrikaAdapter({ counterId: 12345678 })],
},
})Google Analytics 4
import { GoogleAnalyticsAdapter } from '@zavvla/shared-socials/analytics'
new ShareWidget({
metrics: {
adapters: [new GoogleAnalyticsAdapter({ measurementId: 'G-XXXXXXXXXX' })],
},
})Custom Adapter
import type { MetricsAdapter, ShareMetricEvent } from '@zavvla/shared-socials'
class MyAdapter implements MetricsAdapter {
readonly name = 'MyAnalytics'
readonly docsUrl = 'https://my-analytics.example.com'
isAvailable() {
return typeof window.myAnalytics !== 'undefined'
}
track(event: ShareMetricEvent) {
window.myAnalytics.send(event.type, { network: event.network, url: event.url })
}
}
new ShareWidget({ metrics: { adapters: [new MyAdapter()] } })License
MIT © zavvla