Edit in GitHubLog an issue

Panel

A panel is used to display information and options that are persistent and can be shown without blocking user interactions with the active document.

Example of a panel

Panels appear on the left-hand side of the app when user clicks on the Plugins icon at the bottom-left side. Panels do not prevent user interaction with the underlying document and can listen for the user's selection changes. Panels are dismissed in any one of the following manners:

  • The user clicks on the "back arrow" button at the top of XD's Plugins panel
  • The user clicks on one of the other options for the left hand side of the app, such as the Layers panel or Assets panel
  • The user runs a different plugin from the Plugins menu

Usage#

Building the user interface for panels is very similar to modals. Refer to Modal dialog usage.

Building Panels#

You can build panels using any method that creates an HTML5 DOM structure. This means you can use document.createElement, innerHTML, jQuery, React, and other frameworks.

Let's examine a simple panel and how we might create it:

{% tabs sample="Sample", html="HTML", js="JS" %}

{% content "sample" %}

A Simple panel

{% content "html" %}

Copied to your clipboard
1<style>
2 .break {
3 flex-wrap: wrap;
4 }
5 label.row > * {
6 margin: 3px 0;
7 }
8 label.row > span {
9 color: #8e8e8e;
10 width: 20px;
11 text-align: right;
12 font-size: 9px;
13 }
14 label.row input {
15 flex: 1 1 auto;
16 }
17 label.row input[type="number"] {
18 flex-basis: 32px;
19 }
20 div input[type="checkbox"] {
21 flex: 0 0 20px;
22 }
23 form footer > * {
24 position: relative;
25 left: 8px;
26 }
27</style>
28<form method="dialog" id="main">
29 <label class="row" id="fldButtonText">
30 <span>Aa</span>
31 <input
32 type="text"
33 id="txtButtonText"
34 value="Text"
35 placeholder="Text"
36 uxp-quiet="true"
37 />
38 </label>
39 <div class="row break">
40 <label class="row">
41 <span>↕︎</span>
42 <input
43 type="number"
44 uxp-quiet="true"
45 id="txtV"
46 value="10"
47 placeholder="Vertical padding"
48 />
49 </label>
50 <label class="row">
51 <span>↔︎</span>
52 <input
53 type="number"
54 uxp-quiet="true"
55 id="txtH"
56 value="10"
57 placeholder="Horizontal padding"
58 />
59 </label>
60 <div class="row">
61 <input type="checkbox" checked id="chkColor" />
62 <label class="row" id="fldColor">
63 <input
64 type="text"
65 uxp-quiet="true"
66 id="txtColor"
67 value="#0000FF"
68 placeholder="CSS Color"
69 />
70 <span>🎨</span>
71 </label>
72 </div>
73 </div>
74 <footer>
75 <button id="ok" type="submit" uxp-variant="cta">Apply</button>
76 </footer>
77</form>

{% content "js" %}

Copied to your clipboard
1let panel;
2
3function create() {
4 const HTML = `<style>
5 .break {
6 flex-wrap: wrap;
7 }
8 label.row > * {
9 margin: 3px 0;
10 }
11 label.row > span {
12 color: #8E8E8E;
13 width: 20px;
14 text-align: right;
15 font-size: 9px;
16 }
17 label.row input {
18 flex: 1 1 auto;
19 }
20 label.row input[type=number] {
21 flex-basis: 32px;
22 }
23 div input[type=checkbox] {
24 flex: 0 0 20px;
25 }
26 form footer > * {
27 position: relative;
28 left: 8px;
29 }
30 </style>
31 <form method="dialog" id="main">
32 <label class="row" id="fldButtonText">
33 <span>Aa</span>
34 <input type="text" id="txtButtonText" value="Text" placeholder="Text" uxp-quiet="true"/>
35 </label>
36 <div class="row break">
37 <label class="row">
38 <span>↕︎</span>
39 <input type="number" uxp-quiet="true" id="txtV" value="10" placeholder="Vertical padding" />
40 </label>
41 <label class="row">
42 <span>↔︎</span>
43 <input type="number" uxp-quiet="true" id="txtH" value="10" placeholder="Horizontal padding" />
44 </label>
45 <div class="row">
46 <input type="checkbox" checked id="chkColor" />
47 <label class="row" id="fldColor">
48 <input type="text" uxp-quiet="true" id="txtColor" value="#0000FF" placeholder="CSS Color" />
49 <span>🎨</span>
50 </label>
51 </div>
52 </div>
53 <footer><button id="ok" type="submit" uxp-variant="cta">Apply</button></footer>
54 </form>
55 `;
56
57 panel = document.createElement("div");
58 panel.innerHTML = HTML;
59
60 return panel;
61}
62
63function show(event) {
64 // create panel the first time it's shown
65 if (!panel) {
66 panel = create();
67 event.node.appendChild(panel);
68 }
69}
70
71function hide(event) {
72 // in this example, we don't need to do anything when XD hides our panel
73}
74
75function update(selection, root) {
76 console.log(selection.items);
77}
78
79module.exports = {
80 panels: {
81 example: {
82 show,
83 hide,
84 update,
85 },
86 },
87};

{% endtabs %}

Note: you can either reuse your panel's UI nodes, or destroy and recreate the panel each time it's closed. For examples of both approaches, see the detailed documentation on the show() method.

Handling Selection Change#

As you can see in the example above, every time the user's selection changes, your (optional) lifecycle method update will trigger. You will have access to both selection and root as parameters in the function. This means that your panel can display dynamic content based on what user has selected in the document.

{% tabs sampleselection="Sample", htmlselection="HTML", jsselection="JS" %}

{% content "sampleselection" %}

Error message

{% content "htmlselection" %}

Copied to your clipboard
1<style>
2 .break {
3 flex-wrap: wrap;
4 }
5 label.row > * {
6 margin: 3px 0;
7 }
8 label.row > span {
9 color: #8e8e8e;
10 width: 20px;
11 text-align: right;
12 font-size: 9px;
13 }
14 label.row input {
15 flex: 1 1 auto;
16 }
17 label.row input[type="number"] {
18 flex-basis: 32px;
19 }
20 div input[type="checkbox"] {
21 flex: 0 0 20px;
22 }
23 form footer > * {
24 position: relative;
25 left: 8px;
26 }
27</style>
28<form method="dialog" id="main">
29 <label class="row" id="fldButtonText">
30 <span>Aa</span>
31 <input
32 type="text"
33 id="txtButtonText"
34 value="Text"
35 placeholder="Text"
36 uxp-quiet="true"
37 />
38 </label>
39 <div class="row break">
40 <label class="row">
41 <span>↕︎</span>
42 <input
43 type="number"
44 uxp-quiet="true"
45 id="txtV"
46 value="10"
47 placeholder="Vertical padding"
48 />
49 </label>
50 <label class="row">
51 <span>↔︎</span>
52 <input
53 type="number"
54 uxp-quiet="true"
55 id="txtH"
56 value="10"
57 placeholder="Horizontal padding"
58 />
59 </label>
60 <div class="row">
61 <input type="checkbox" checked id="chkColor" />
62 <label class="row" id="fldColor">
63 <input
64 type="text"
65 uxp-quiet="true"
66 id="txtColor"
67 value="#0000FF"
68 placeholder="CSS Color"
69 />
70 <span>🎨</span>
71 </label>
72 </div>
73 </div>
74 <footer>
75 <button id="ok" type="submit" uxp-variant="cta">Apply</button>
76 </footer>
77</form>

{% content "jsselection" %}

Copied to your clipboard
1let panel;
2
3function create() {
4 const HTML = `<style>
5 .break {
6 flex-wrap: wrap;
7 }
8 label.row > * {
9 margin: 3px 0;
10 }
11 label.row > span {
12 color: #8E8E8E;
13 width: 20px;
14 text-align: right;
15 font-size: 9px;
16 }
17 label.row input {
18 flex: 1 1 auto;
19 }
20 label.row input[type=number] {
21 flex-basis: 32px;
22 }
23 div input[type=checkbox] {
24 flex: 0 0 20px;
25 }
26 form footer > * {
27 position: relative;
28 left: 8px;
29 }
30
31 </style>
32 <form method="dialog" id="main">
33 <label class="row" id="fldButtonText">
34 <span>Aa</span>
35 <input type="text" id="txtButtonText" value="Text" placeholder="Text" uxp-quiet="true"/>
36 </label>
37 <div class="row break">
38 <label class="row">
39 <span>↕︎</span>
40 <input type="number" uxp-quiet="true" id="txtV" value="10" placeholder="Vertical padding" />
41 </label>
42 <label class="row">
43 <span>↔︎</span>
44 <input type="number" uxp-quiet="true" id="txtH" value="10" placeholder="Horizontal padding" />
45 </label>
46 <div class="row">
47 <input type="checkbox" checked id="chkColor" />
48 <label class="row" id="fldColor">
49 <input type="text" uxp-quiet="true" id="txtColor" value="#0000FF" placeholder="CSS Color" />
50 <span>🎨</span>
51 </label>
52 </div>
53 </div>
54 <footer><button id="ok" type="submit" uxp-variant="cta">Apply</button></footer>
55 </form>
56 `;
57
58 panel = document.createElement("div");
59 panel.innerHTML = HTML;
60
61 return panel;
62}
63
64function show(event) {
65 // create panel the first time it's shown
66 if (!panel) {
67 panel = create();
68 event.node.appendChild(panel);
69 }
70}
71
72function hide(event) {
73 // in this example, we don't need to do anything when XD hides our panel
74}
75
76function update(selection, root) {
77 const { Text } = require("scenegraph");
78 if (!(selection.items[0] instanceof Text)) {
79 panel.innerHTML = `<p>Please select a text object.</p>`;
80 }
81}
82
83module.exports = {
84 panels: {
85 example: {
86 show,
87 hide,
88 update,
89 },
90 },
91};

{% endtabs %}

Further Reading#

Refer to the panel lifecycle method documentation to learn more about these methods:

Was this helpful?
Copyright © 2021 Adobe. All rights reserved.