Реалізація Side Panel браузерного розширення (Chrome)
Side Panel — бокова панель Chrome, яка з'явилась у Chrome 114. Вона працює як постійна панель поруч з контентом сторінки, не закривається при переключенні вкладок та має значно більше місця, ніж Popup. Це перший нативний механізм для «прикріплених» інтерфейсів у Chrome.
Відмінності Side Panel від Popup
| Характеристика | Popup | Side Panel |
|---|---|---|
| Ширина | 800 px макс | ~400 px (фіксована Chrome) |
| Життєвий цикл | До втрати фокусу | Постійна, переживає зміну вкладок |
| Контекст вкладки | Привязана до активної | Може бути глобальною або per-tab |
| Доступність | З Chrome 4 | З Chrome 114 |
| Firefox/Safari | Немає аналога | Немає аналога |
Підключення у Manifest V3
{
"manifest_version": 3,
"name": "My Side Panel Extension",
"version": "1.0.0",
"permissions": ["storage", "tabs", "activeTab", "scripting", "sidePanel"],
"background": {
"service_worker": "background.js"
},
"action": {
"default_icon": "icons/icon48.png",
"default_title": "Відкрити панель"
},
"side_panel": {
"default_path": "panel/panel.html"
}
}
Відкриття панелі при кліку на іконку
За замовчуванням клік на іконку розширення нічого не робить з Side Panel. Потрібно явно налаштувати поведінку:
// background.js (Service Worker)
// Варіант 1: відкривати панель при кожному кліку на іконку
chrome.sidePanel
.setPanelBehavior({ openPanelOnActionClick: true })
.catch(console.error);
// Варіант 2: відкривати програмно (потребує user gesture)
chrome.action.onClicked.addListener(async (tab) => {
await chrome.sidePanel.open({ tabId: tab.id });
});
Per-tab vs глобальна панель
Панель може бути різною для кожної вкладки або спільною для всіх:
// background.js
// Різна панель залежно від сайту
chrome.tabs.onUpdated.addListener(async (tabId, info, tab) => {
if (info.status !== 'complete') return;
if (tab.url?.includes('github.com')) {
await chrome.sidePanel.setOptions({
tabId,
path: 'panel/github-panel.html',
enabled: true,
});
} else if (tab.url?.includes('figma.com')) {
await chrome.sidePanel.setOptions({
tabId,
path: 'panel/design-panel.html',
enabled: true,
});
} else {
// Вимкнути панель для звичайних сторінок
await chrome.sidePanel.setOptions({ tabId, enabled: false });
}
});
React-застосунок у Side Panel
Структура panel/panel.html аналогічна Popup, але має більше місця:
// panel/App.tsx
import { useEffect, useState, useRef } from 'react';
import browser from 'webextension-polyfill';
export function SidePanel() {
const [notes, setNotes] = useState<string[]>([]);
const [currentUrl, setCurrentUrl] = useState('');
const portRef = useRef<browser.Runtime.Port | null>(null);
useEffect(() => {
// Постійне з'єднання з background для потокування даних
portRef.current = browser.runtime.connect({ name: 'side-panel' });
portRef.current.onMessage.addListener((msg) => {
if (msg.type === 'PAGE_CHANGED') {
setCurrentUrl(msg.url);
loadNotesForUrl(msg.url);
}
});
return () => portRef.current?.disconnect();
}, []);
return (
<div className="side-panel">
<header className="side-panel__header">
<h2>Замітки</h2>
</header>
{/* Вміст панелі */}
</div>
);
}
Терміни
Базова side panel з замітками: 2–3 дні. Складна з синхронізацією та per-tab логікою: 5–7 днів.







