Anvil Community Forum

Does a GridPanel inside an alert have only 8 columns?

Is the GridPanel documentation wrong when it says “Each row has twelve columns” or is the GridPanel not working as expected?

  1. If I put a GridPanel inside an alert with large=True, then the GridPanel has 12 columns.
    This works as documented and expected.

  2. If I add more than 12 items to a row, the items in excess spill into the next row.
    This is not documented and unexpected. I would rather have an error than components on the wrong place, but I can live with it. I’m not going to complain when I get into trouble because I’m looking for trouble.

  3. If I put a GridPanel inside an alert with large=False, then the GridPanel has 8 columns instead of 12.
    This is undocumented, unexpected and I don’t like it.

for n in range(15):
  grid_panel.add_component(Label(text=str(n)), row='x', col_xs=n, width_xs=1)

I am working on a custom component that could be used in an alert, and the custom component doesn’t know whether the alert is large or not, or even whether it is inside an alert or not.

I used a GridPanel assuming that its behavior would be predictable, but apparently I was wrong.

So my question is:

  • Can a GridPanel know how many columns it has?
  • If not, is the 8 column behavior described above an error and are there plans to fix it any time soon?
  • If not, can I have some directions on how to use a ColumnPanel from code?

I understand that working from code with a ColumnPanel is intentionally undocumented and it’s going to be difficult, but better difficult than wrong.

I tried to reverse engineer the behavior looking at how it is stored in the yaml file, but I failed miserably.


Well… may be there aren’t 8 columns after all, it just has as many columns as it likes.

Here is what happens if I add 15 labels on the same row and on 15 different columns: only 8 fit on the same row, while there seem to be 12 columns if I only put one label per row, but the last 2 columns on the right are not visible:

for n in range(15):
  grid_panel.add_component(Label(text=str(n)), row='x', col_xs=n, width_xs=1)

for n in range(15):
  grid_panel.add_component(Label(text=str(n)), row=f'r{n}', col_xs=n, width_xs=1)

At this point I need to abandon the GridPanel. It’s too unpredictable.
I will try with an XYPanel.

Just to address part of this:

All grid panels have 12 columns even inside narrow alerts.

What we’re seeing in the narrow alert is the 12 columns wrapping their container when there’s not enough space.

    def btn_click(self, **event_args):
        """This method is called when the button is clicked"""
        gp = GridPanel()
        w = 6 # 1, 2, 3, 4, 6, 12
        for j in range(10):
            for i in range(12//w):
                l = Label(text=f"{j}-{i}")
                gp.add_component(l, row=j, col_xs=i*w, width_xs=w)

If you try setting w to different factors of 12, you’ll see that 12 columns is consistent.

Under the hood the width is set to a percentage of the width available.
e.g. if we set w=3 we get 4 labels.
Each label takes up 25% of the container’s width.

When you get to w=1, it’ll wrap because of the width constraint.
The label tries to take up 1/12th of the container width…
But because the labels width is larger than 1/12th of the width, something’s got to give… and so it wraps.
(note the label widths are too large because of some css padding - with some css adjustment there’s no wrapping - see end of post)

Screenshot 2022-04-15 at 21.14.15

When exceeding 12 columns there has to be wrapping for the same reason.

e.g. in the same scenario with w=3 labels still aim to take up 25% of the width…
But if you try doing 18 columns instead of 12 that’s 150% of the overall width, so they wrap.

An exception would probably have been better here in the too many columns scenario.

I used the following css in the above images (both images are inside narrow alerts):

.grid-panel .row {
    margin-left: 0;
  	margin-right: 0;

.grid-panel .row > div {
    padding-right: 1px;
    padding-left: 1px;

I think you addressed it all, in great detail.

The summary is that there are 12 columns, assuming that the content on each column, including its padding fits in the 8.33% of the panel width.

I was experimenting with the GridPanel while working on the InputBox. I ended up with using a LinearPanel with a bunch of FlowPanels and setting the width of each component from code.

I calculate the widths and use px instead of % assuming that the width of the alert is 546 if self.large else 246, which could cause it to break if the css for the alert changes. For now it works well enough.

1 Like