UnityDynamicPanels
Draggable, resizable, dockable and stackable UI panel solution for Unity 3D
Install / Use
/learn @yasirkula/UnityDynamicPanelsREADME
Dynamic Panels for Unity 3D
(used external assets in screenshots: In-game Debug Console and Runtime Inspector & Hierarchy)
Available on Asset Store: https://assetstore.unity.com/packages/tools/gui/dynamic-panels-114126
Forum Thread: https://forum.unity.com/threads/released-dynamic-panels-draggable-resizable-dockable-and-stackable-ui-panels.523106/
Discord: https://discord.gg/UJJt549AaV
WebGL Demo: http://yasirkula.net/DynamicPanelsDemo/
ABOUT
This asset helps you create dynamic panels using Unity's UI system. These panels can be dragged around, resized, docked to canvas edges or to one another and stacked next to each other as separate tabs.
FEATURES
- Supports all canvas modes (Screen Space and World Space)
- Supports multiple canvases (panels can be moved between canvases by dragging)
- Has an extensive Scripting API to create/manipulate panels by code
- Each panel costs 3 additional batches (this number can increase with each tab using a custom icon)
INSTALLATION
There are 5 ways to install this plugin:
- import DynamicPanels.unitypackage via Assets-Import Package
- clone/download this repository and move the Plugins folder to your Unity project's Assets folder
- import it from Asset Store
- (via Package Manager) click the + button and install the package from the following git URL:
https://github.com/yasirkula/UnityDynamicPanels.git
- (via OpenUPM) after installing openupm-cli, run the following command:
openupm add com.yasirkula.dynamicpanels
FAQ
- New Input System isn't supported on Unity 2019.2.5 or earlier
Add ENABLE_INPUT_SYSTEM compiler directive to Player Settings/Scripting Define Symbols (these symbols are platform specific, so if you change the active platform later, you'll have to add the compiler directive again).
- "Unity.InputSystem" assembly can't be resolved on Unity 2018.4 or earlier
Remove Unity.InputSystem assembly from DynamicPanels.Runtime Assembly Definition File's Assembly Definition References list.
HOW TO
Add Dynamic Panels Canvas component to the RectTransform inside which your panels will reside. This RectTransform doesn't have to be the Canvas object itself, it can be a child of the canvas and it can have a custom size.
There are two ways to create panels: by using the GUI of Dynamic Panels Canvas or via Scripting API. There are also two types of panels: free panels that can be moved around and resized freely and docked panels that are moved by the layout system, depending on where it is docked to. A panel can have multiple tabs.

To add a new free panel using the Dynamic Panels Canvas component, simply click the Add New button under the Free Panels section. Then, click the + button to start adding tabs to that panel. Each tab has 4 properties: the content (RectTransform) that will be displayed while the tab is active, a label, an optional icon, and the minimum size of the content associated with the tab. To remove a free panel, select a tab inside the panel and click the Remove Selected button.
You can create docked panels by using the buttons under the Docked Panels section. To create a panel that is docked to the edge of the Dynamic Panels Canvas, use the buttons next to "Dock new panel to canvas:". You can click a panel inside the preview zone (immediately under the Docked Panels section) and edit its tabs. You can also dock a panel to the selected panel using the buttons next to "Dock new panel inside:".
When you are done, click the Play button to see the magic happen!
There are a couple of settings in Dynamic Panels Canvas that you may want to tweak:
- Leave Free Space: when enabled, there will always be some free space in the canvas that docked panels can't fill. Otherwise, docked panels will fill the whole canvas
- Minimum Free Space: if Leave Free Space is enabled, this value will determine the minimum free space
- Free Space Target Transform: if Leave Free Space is enabled and a RectTransform is assigned to this variable, the RectTransform's properties will automatically be updated to always match the free space's position and size
- Prevent Detaching Last Docked Panel: when enabled, trying to detach the last docked panel from the canvas will automatically fail
- Panel Resizable Area Length: size of the invisible resize zones at each side of the panels that allow users to resize the panels
- Canvas Anchor Zone Length: size of the Dynamic Panels Canvas' drop zones. When a tab is dragged and dropped onto that area, it will be docked to that edge of the Dynamic Panels Canvas
- Panel Anchor Zone Length: size of the panels' drop zones. When a tab is dragged and dropped onto that area, it will be docked to that panel. This area is enabled only for docked panels (you can't dock panels to free panels)
- Initial Size: (docked panels only) determines the initial size of a docked panel. This is achieved by programmatically resizing the panel after it is created, so this operation may affect the adjacent panels' sizes, as well. This value won't have any effect if left as (0,0)
NOTE: if you change the Resources/DynamicPanel.prefab, also make sure that the Panel's Header Height property is equal to the distance between the top of the panel and the bottom of the PanelHeader child object (which holds the tabs at runtime).
PanelCursorHandler
Adding this component to a GameObject will make the cursor dynamic i.e. its texture will change when it enters a panel's resizable area.

Note that this component won't have any effect on Android and iOS.
SCRIPTING API
Before using the scripting API, import DynamicPanels namespace to your script(s): using DynamicPanels;
PanelUtils
static Panel CreatePanelFor( RectTransform content, DynamicPanelsCanvas canvas ): creates and returns a panel with a tab that is associated with the content. The panel is created inside the specified Dynamic Panels Canvas. If the content is already part of a panel, then the existing panel is returned
static PanelTab GetAssociatedTab( RectTransform content ): if content is associated with a tab, returns it; otherwise returns null
Panel
DynamicPanelsCanvas Canvas { get; }: returns the Dynamic Panels Canvas that this panel currently belongs to
PanelGroup Group { get; }: returns the PanelGroup that this panel currently belongs to (more on that later)
Vector2 Position { get; }: returns the anchored position of the panel. The anchor of a panel is located at its bottom-left corner
Vector2 Size { get; }: returns the size of the panel
Vector2 MinSize { get; }: returns the minimum size of the panel. This value is calculated at runtime using the minimum size values of the panel's tab(s)
int NumberOfTabs { get; }: returns the number of tabs the panel has
int ActiveTab { get; set; }: returns the index of the currently selected tab. Its value can be changed, as well
PanelTab this[int tabIndex] { get; }: returns the tab at the specified index
bool IsDocked { get; } }: returns whether the panel is a docked panel or a free panel
PanelTab AddTab( RectTransform tabContent, int tabIndex = -1 ): adds a new tab to the panel and sets tabContent as its content. If tabIndex is not specified, then the tab will be inserted at the end of the tabs list. Newly created tabs will have default label/icon/minimum size values, so it is highly recommended to customize these values afterwards
PanelTab AddTab( PanelTab tab, int tabIndex = -1 ): moves the specified tab to this panel
PanelTab AddTab( string tabID, int tabIndex = -1 ): same as above
void RemoveTab( int tabIndex ): removes a tab from the panel. Be careful when calling this function because the content associated with the tab will also be destroyed!
void RemoveTab( PanelTab tab ): same as above
void RemoveTab( string tabID ): same as above
int GetTabIndex( RectTransform tabContent ): returns the index of a tab, or -1 if the tab is not part of the panel
int GetTabIndex( PanelTab tab ): same as above
int GetTabIndex( string tabID ): same as above
PanelTab GetTab( RectTransform tabContent ): returns the tab that is associated with tabContent, or null if it is not a part of the panel
void DockToRoot( Direction direction ): docks the panel to an edge of the Dynamic Panels Canvas
void DockToPanel( IPanelGroupElement anchor, Direction direction ): docks the panel to another panel or panel group. It is not possible to dock a panel to a free panel
void Detach(): if the panel is docked, detaches it so that it becomes a free panel
Panel DetachTab( int tabIndex ): detaches a tab from the panel, creates a new panel with it and returns the new panel. If the tab is the only tab that the panel has, then the panel itself is detached and returned
Panel DetachTab( PanelTab tab ): same as above
Panel DetachTab( string tabID ): same as above
void BringForward(): if the panel is free, brings it forwards so that it is drawn above all other panels
void MoveTo( Vector2 screenPoint ): moves the panel to the specified point on the screen (panel's center will be aligned to the point)
void ResizeTo( Vector2 newSize ): resizes the panel. If it is docked, then this change may also affect the adjacent panels
`bool CanResizeInDirection( Direction direc
Related Skills
node-connect
350.1kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
109.9kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
350.1kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
350.1kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
