apps-script-uilisted
Install: claude install-skill bootgs/skills
# Apps Script UI
## Menus
`onOpen()` runs automatically when the file opens and builds the menu:
```ts
function onOpen(): void {
SpreadsheetApp.getUi()
.createMenu("My Add-on")
.addItem("Do Something", "doSomething")
.addSeparator()
.addSubMenu(SpreadsheetApp.getUi().createMenu("More").addItem("Option A", "optionA"))
.addToUi();
}
```
Menu item callbacks are referenced **by function name as a string**, not a reference — the function must be public (see Gotchas) and take no arguments.
## Sidebars
```ts
function showSidebar(): void {
const html = HtmlService.createHtmlOutput('<h3>Quick Entry</h3><input id="value"><button onclick="submit()">Add</button>')
.setTitle("Quick Entry")
.setWidth(300);
SpreadsheetApp.getUi().showSidebar(html);
}
```
Client-side JS in the HTML calls server functions through `google.script.run`:
```html
<script>
function submit() {
google.script.run
.withSuccessHandler((result) => alert("Added!"))
.withFailureHandler((err) => alert("Error: " + err.message))
.addEntry(document.getElementById("value").value);
}
</script>
```
## Modal dialogs and the progress-spinner pattern
For anything that takes more than a second or two, show a blocking modal with a spinner instead of leaving the UI frozen with no feedback:
```ts
function showProgress(message: string, serverFunctionName: string): void {
const html = HtmlService.createHtmlOutput(`
<div class="spinner"></div>
<div id="msg">${