Add-on Button set and getting smaller buttons

37 views
Skip to first unread message

Mike Castle

unread,
Jul 5, 2025, 3:38:53 AMJul 5
to google-apps-sc...@googlegroups.com
Or, any good recommendations for pagination in a Card?

I have an Addon where I'm hitting the limit for the number of widgets in a card.

I'm pondering adding pagination capabilities to it (I'd done similar years ago in the UiApp days).

I'm doing it using a ButtonSet full of TextButton()s like:
[<-] [1] [...] [4] [5] [6] [...] [10] [->]

Of course, since the side panel is fairly small, it actually gets rendered like this:

[<-] [1] [...] [4]
 [5] [6] [...] [10]
 [->]

Where numbers are set via .setText() and the arrow and ... buttons use .setMaterialIcon()

The buttons with text in them are pretty wide,  with lots of unused space in the actual button.

Is there a way I can restyle the buttons to not be so wide?  I've been searching, but no luck so far.

Alternatively, if anyone has a pointer to a nice way to do pagination with Cards, that would be great, too.

image.png
Thanks,
mrc

PS: I like the use of ellipses to go to the page between the numbers.  E.g., (1+4)/2 => 2, (6+10)/2 => 8 .  In my UiApp, I had hundreds of pages, and this was really quick to get to the one I wanted.. Quicker than having a field to type into to go to page X.

Google Pony

unread,
Jul 10, 2025, 4:02:25 AMJul 10
to Google Apps Script Community

Hi Mike,


I understand your challenge with pagination buttons in a Google Workspace Add-on. Here are a few suggestions to address your issue:


1. Reducing Button Width

 Use Icons Instead of Text: Since MaterialIcon buttons are more compact, consider replacing numbered buttons (e.g., [1], [2]) with icons (e.g., [1️⃣], [2️⃣]) where feasible. While this may not be ideal for all use cases, it can save space.

 Custom CSS (Limited): Google Apps Script does not support direct CSS styling for buttons, but you can experiment with .setText() to use shorter labels (e.g., [Pg 1][1]).


2. Alternative Pagination UI

 Dropdown Menu: Replace the button set with a SelectionInput dropdown for page selection. This is more compact and works well for large page ranges.

var dropdown = CardService.newSelectionInput()
    .setType(CardService.SelectionInputType.DROPDOWN)
    .setTitle("Page")
    .setFieldName("page");
for (var i = 1; i <= totalPages; i++) {
    dropdown.addItem(`Page ${i}`, i.toString(), i === currentPage);

} 


Prev/Next Only: Simplify to just two buttons (← and →) and dynamically update the card content on navigation. Add a small TextParagraph to display the current page (e.g., "Page 5 of 10").


3. Ellipses Logic Improvement

 Your ellipses logic ((1+4)/2 => 2) is clever! To make it more intuitive, you could:

 Replace [...] with a ButtonSet of two buttons: [<<] (jump backward) and [>>] (jump forward).

 Use a TextInput for direct page entry (though this requires handling user input validation).


4. Example Code for Dynamic Buttons

 Here’s a snippet to dynamically generate a compact button set:

const createPaginationButtons = (currentPage, totalPages) => {
    var buttonSet = CardService.newButtonSet();
    // Add Previous button
    if (currentPage > 1) {
        buttonSet.addButton(
            CardService.newTextButton()
                .setText("←")
                .setOnClickAction(CardService.newAction().setFunctionName("gotoPage").setParameters({page: currentPage - 1}))
        );
    }
    // Add dynamic page buttons (e.g., [1] [...] [4] [5] [6] [...] [10])
    // ... your logic here ...
    // Add Next button
    if (currentPage < totalPages) {
        buttonSet.addButton(
            CardService.newTextButton()
                .setText("→")
                .setOnClickAction(CardService.newAction().setFunctionName("gotoPage").setParameters({page: currentPage + 1}))
        );
    }
    return buttonSet;
}


5. Further Reading

[Cards Reference](https://developers.google.com/apps-script/reference/card-service) for UI limitations.

Consider using a Navigation object to refresh the card without full reloads (better performance).


If you’d like a more detailed example or have specific constraints, feel free to share more details!


Sandeep Kumar Vollala
Consultant
LinkedIn Logo WhatsApp Logo

Mike Castle

unread,
Jul 11, 2025, 5:24:21 PMJul 11
to google-apps-sc...@googlegroups.com
Thanks for the followup!

I had actually meant to do a followup on my own about my solution.

I did end up going with a combination of a  `prev`, `refresh`, `next` icon-only TextButtons on one row and and a drop down list on the next row (and since it the default of the drop down is set to be the current page, it provides that "Page X of Y" information.

The reason I ended up wanting the reset is, depending on what the user does, the number of items in the list can change.  It happens to be in the form of "Give item X weight N" and it only lists exceptions.  So if the user ends up setting the value back to the default, it is automatically removed, so going forward one page then backwards could result in a different set of items on the page.  And since the handler for updating the field is different from the handler rendering the Card, well, I have just been too lazy to figure out how to make one widget to tell the holding Card to refresh itself.  Maybe someday.  (After all, the total number of users for this Add-on is "one".  :-)

I hadn't realized that there were material icons for numbers.  I'll have to check that out.  Since the number of pages can be greater than two digits, I'd have to figure out how to do that.  But it sounds promising.

I'm also explicitly using TextButtons because ImageButtons do not support ".setDisabled()".  I see there is a feature request for that, and added some comments to it.

I wish that FixedFooter allows something more than just two buttons.  Having a nav panel in the same location rather than at the bottom of a list that can change size due to line wraps is preferable.

Cheers!
mrc


Reply all
Reply to author
Forward
0 new messages