UIListLayout & UIGridLayout in Roblox — Complete Roblox Guide
Last updated: 2026-06-20 · 724 words · 4 min read
UIListLayout and UIGridLayout are the two layout objects you will use in 90% of Roblox GUIs. Used correctly they eliminate the manual math behind "position the second item 8 px below the first" and adapt automatically when items are added, removed, or sorted. Used incorrectly they fight your AnchorPoint and your scrolling frames. This guide covers when to pick which, how padding and sort order really work, and how to wrap them in a ScrollingFrame for long lists.
When to use UIListLayout
UIListLayout stacks children in a single direction — vertical or horizontal. It is perfect for leaderboards, settings rows, chat messages, hotbar slots, and dialogue choice buttons. The layout reads each child's LayoutOrder property and sorts them ascending; siblings with no LayoutOrder fall to the bottom in undefined order. Set FillDirection to control axis, HorizontalAlignment / VerticalAlignment for cross-axis alignment, and Padding for the gap between items. The container's CanvasSize / AbsoluteContentSize updates automatically, which is what makes auto-resizing ScrollingFrames possible.
local list = Instance.new("UIListLayout")
list.FillDirection = Enum.FillDirection.Vertical
list.HorizontalAlignment = Enum.HorizontalAlignment.Center
list.VerticalAlignment = Enum.VerticalAlignment.Top
list.SortOrder = Enum.SortOrder.LayoutOrder
list.Padding = UDim.new(0, 8)
list.Parent = containerWhen to use UIGridLayout
UIGridLayout arranges children in a 2D grid with fixed cell size. Use it for inventories, shop cards, ability hotbars, sticker books, and pet collections. Cells stay square (or whatever ratio CellSize defines) regardless of the parent size, and rows wrap automatically when the parent runs out of room. CellPadding is the gap between cells; FillDirection controls whether items flow row-first or column-first. The trade-off vs UIListLayout: cells are fixed-pixel, so on a small screen you may see only two columns where you expected four.
local grid = Instance.new("UIGridLayout")
grid.CellSize = UDim2.new(0, 100, 0, 100)
grid.CellPadding = UDim2.new(0, 8, 0, 8)
grid.FillDirection = Enum.FillDirection.Horizontal
grid.SortOrder = Enum.SortOrder.LayoutOrder
grid.Parent = containerLayoutOrder — the property nobody mentions
Both layouts honor each child's LayoutOrder when SortOrder is set to LayoutOrder. This is how you re-order a leaderboard without re-parenting children: just update the LayoutOrder values. Tip: leave gaps (10, 20, 30) instead of (1, 2, 3) so you can insert items without renumbering. Set SortOrder.Name to sort alphabetically by Instance name, or default to creation order if you do not care.
Wrapping in a ScrollingFrame
For long lists or grids that exceed the visible area, parent the layout container inside a ScrollingFrame and set AutomaticCanvasSize to Y (or X for horizontal lists). The ScrollingFrame reads the layout's AbsoluteContentSize and resizes its CanvasSize to match — no manual canvas sizing. Pair with CanvasSize = UDim2.new(0,0,0,0) and AutomaticCanvasSize = Enum.AutomaticSize.Y for the cleanest result.
local scroll = Instance.new("ScrollingFrame")
scroll.Size = UDim2.new(1, 0, 1, 0)
scroll.CanvasSize = UDim2.new(0, 0, 0, 0)
scroll.AutomaticCanvasSize = Enum.AutomaticSize.Y
scroll.ScrollBarThickness = 6
scroll.Parent = parent
local list = Instance.new("UIListLayout")
list.SortOrder = Enum.SortOrder.LayoutOrder
list.Padding = UDim.new(0, 8)
list.Parent = scrollUIPadding — the inset you keep forgetting
Layouts measure spacing between children, not from the container edge. Without UIPadding, your top item sits flush against the container border. Add a UIPadding sibling to the layout (parent both to the container) with PaddingTop / PaddingBottom / PaddingLeft / PaddingRight to inset the entire content from the edge. Common values: 12 px on small panels, 24 px on full-screen modals.
Performance and lifecycle gotchas
Layouts run on every frame change, but the cost is negligible until you cross ~200 children. If you are rendering a 50-row leaderboard, that is fine. If you are rendering a 5000-row inventory, virtualize: only instantiate visible rows and reuse the same Frame instances as the player scrolls. The second gotcha is ordering: if you parent a child into a UIListLayout container before setting LayoutOrder, the layout will sort once with the default value and once with the new value — two layout passes per insert. Set LayoutOrder before parenting to avoid the double-sort. The third gotcha is mixing layouts: do not put a UIListLayout and a UIGridLayout under the same parent. Roblox honors the first one it finds and ignores the second silently. Use nested containers if you need both behaviors.
Migrating from manual positioning
If you inherited a project that positions every child by hand, you can migrate to UIListLayout in three steps. First, sort the children by their current Y offset and assign LayoutOrder values in the same order — the layout will reproduce the original visual stacking. Second, add the UIListLayout instance to the parent. Third, reset every child's Position to UDim2.new(0, 0, 0, 0); the layout overrides positions, so any leftover offsets just become noise. Save before each step — the rollback path is to delete the layout instance.
Step-by-step summary
- 1
Pick the right layout object
Add UIListLayout for stacks (leaderboards, settings rows). Add UIGridLayout for 2D grids (inventories, shop cards).
- 2
Set padding and sort order
Use LayoutOrder for explicit ordering and Padding for the gap between items. Default SortOrder to LayoutOrder.
- 3
Wrap in a ScrollingFrame for long lists
Parent the container inside a ScrollingFrame with AutomaticCanvasSize = Y so the canvas resizes automatically.
- 4
Add UIPadding for edge inset
Without UIPadding, items sit flush against the container border. Add 12–24 px on each side for breathing room.
- 5
Test with dynamic content
Add and remove children at runtime to confirm the layout reflows. UIListLayout handles this for free; UIGridLayout may run out of columns on small screens.
FAQ
Can I nest UIListLayout inside UIGridLayout?
Yes. A common pattern: UIGridLayout for the outer 3×3 of cards, UIListLayout inside each card to stack the title, description, and Buy button vertically.
Why does my UIGridLayout cut off rows?
Most likely the parent's Size is too small to fit a full row of CellSize × CellPadding. Either shrink CellSize, set the parent to AutomaticSize = Y, or wrap in a ScrollingFrame.
What is the difference between SortOrder.Name and SortOrder.LayoutOrder?
Name sorts alphabetically by the Instance.Name string. LayoutOrder sorts by the integer LayoutOrder property. Use LayoutOrder for predictable game logic; use Name for designer-friendly trees.