Перейти до вмісту
tatetUI

ResizablePanels

Дві панелі з pointer resize, збереженням ширини в localStorage та доступним separator-контролем.

Приклад

Навігація

Перетягніть роздільник або використайте стрілки.

Робоча область

Розмір панелей відновиться з localStorage.

Роздільник-лінія

Типовий роздільник — смуга 11px з лінією посередині: її видно й легко влучити. Для інтерфейсів, де панелі й так розділені межею (список чатів і переписка), separator-style="line" лишає між ними лише лінію 1px. Зона захоплення не зменшується — це невидима смуга 12px навколо лінії (48px на дотику), а ручка й акцентна підсвітка з'являються на наведенні, фокусі та під час перетягування.

Чати

Лінія замість смуги: наведіть курсор, щоб побачити ручку.

Переписка

Згорнута панель

Бічну панель, яку відкривають і закривають (чат поруч із відео, інспектор поруч із полотном), не варто виносити з компонента через v-if: тоді основна панель перемонтовується, і відео чи прокрутка в ній починаються наново. collapsed="end" (або "start") ховає панель разом із роздільником через display: none, решта займає все місце, а вміст обох лишається змонтованим. Ширина не скидається — розгорнута панель повертається до попередньої.

Основна область

Стан тут не скидається, коли бічна панель ховається.

Бічна панель

Розсуньте її — після повторного відкриття ширина та сама.

API

Props

НазваТипТиповоОпис
modelValuenumberundefinedРозмір першої панелі у відсотках. Використовуйте через `v-model`.
minnumber20Мінімальний розмір першої панелі у відсотках.
maxnumber80Максимальний розмір першої панелі у відсотках.
stepnumber5Крок зміни розміру стрілками з клавіатури.
directionverticalhorizontal"horizontal"Вісь поділу: панелі поруч чи одна над одною.
storageKeystringundefinedКлюч localStorage, під яким зберігається розмір між сесіями. Збережене значення читається один раз у onMounted і заявляється через звичайний `update:modelValue`; запис відбувається лише після дії користувача (drag або клавіатура) — сторонні зміни `modelValue` збереженого значення не перезаписують. Значення — голе число, тож ключ має бути версіонованим: зміна сенсу числа вимагає нового ключа, а не «захисного» парсера.
startClassstringundefinedКлас першої панелі (`<section>`): напр. адаптивне приховування.
endClassstringundefinedКлас другої панелі (`<section>`).
separatorClassstringundefinedКлас роздільника: напр. прибрати його разом із прихованою панеллю.
separatorStylebandline"band"Вигляд роздільника. `band` — смуга 11px з лінією посередині (типово). `line` — лише лінія 1px між панелями, як межа в застосунках-месенджерах; зона захоплення лишається 12px (48px на дотику) — невидима, навколо лінії.
collapsedstartendundefinedЗгорнути одну з панелей: вона й роздільник ховаються (`display: none`), інша займає все місце. Вміст згорнутої панелі й сусідньої лишається змонтованим — відео чи прокрутка в основній панелі не перезапускаються, коли бічна відкривається й закривається. Розмір (`modelValue`, storage) не змінюється: розгорнута панель повертається до попередньої ширини.
startLabelstring"Перша панель"Доступна назва першої панелі.
endLabelstring"Друга панель"Доступна назва другої панелі.
separatorLabelstring"Змінити розмір панелей"Доступна назва роздільника. Він оголошений як `separator` з `aria-valuenow`, тож без назви скрінрідер зачитає лише відсоток.
disabledbooleanfalse—

Події

НазваPayloadОпис
update:modelValue[value: number]Частка першої панелі у відсотках. Емітується після drag, клавіатури та при відновленні збереженого розміру.
change[value: number]Фінальне значення після keyboard або pointer дії.

Слоти

НазваОпис
startВміст першої панелі. `size` — її поточний розмір у відсотках.
endВміст другої панелі. `size` — розмір ПЕРШОЇ панелі у відсотках.

Коли використовувати

Для редакторів, файлових менеджерів і dashboard, де користувачу потрібно розподіляти місце між двома одночасно важливими областями.

Збереження ширини (storage-key) — саме для таких екранів: оператор, який щодня розсуває список товарів на 40%, не має робити цього двічі. Компонент сам читає значення в onMounted і сам записує його після дії користувача — батьківській сторінці не потрібно тримати ні стан, ні власний localStorage-ключ.

Коли НЕ використовувати

Не використовуйте resize, якщо одна панель є тимчасовою — тоді краще Drawer. На вузьких екранах часто зрозуміліше скласти блоки вертикально без separator: для цього панелям і роздільнику можна передати адаптивні класи (start-class, end-class, separator-class), напр. max-md:hidden, і вузький екран залишиться з одною панеллю без жодного JS.

Збереження розміру

storage-key вимикає необхідність у v-model повністю: компонент зберігає останню встановлену ширину і відновлює її наступного разу.

  • відновлення відбувається в onMounted — перший (серверний) рендер дає дефолт, клієнтський застосовує збережене значення до першої взаємодії;
  • запис — лише після дії користувача (drag або клавіатура): зміни modelValue ззовні не перезаписують збережену ширину;
  • значення — голе число (частка першої панелі у відсотках), тож ключ версіонуйте: зміна сенсу числа вимагає нового ключа, а не парсера.

Доступність

Роздільник має role="separator", значення min/max/now і правильну orientation. Arrow-клавіші змінюють розмір на step, Home та End переходять до меж. Disabled separator вилучається з tab order.

Видимий роздільник — 11px, і пальцем у нього не влучити. На coarse-вказівнику ціль розширює невидима смуга 45px уздовж роздільника; вона трохи заходить на краї панелей, як і hitAreaMargins у react-resizable-panels.

Портування

Компонент не має зовнішніх залежностей і сам імпортує все з vue — onMounted у тому числі. У проєктах без Nuxt-автоімпортів (чистий Vite, Vitest) це різниця між «працює» і ReferenceError.

Корінь несе h-full w-full: компонент заповнює батька цілком. У flex-батьку без цього він мірявся контентом, і права панель залишала порожній хвіст.