A 2D grid of Service Item tiles used for top-level service navigation. Column (2–5) sets the tiles across, Row (1–5) the tiles down.
Column=4, Row=2) — string values are the correct approach here, since Figma variant properties cannot be typed as integers. Interaction states are owned by the Service Item child and are assessed there, not on this layout container. Code Connect mappings are left open for engineering to register.Contexts are illustrative. Final screens will reference actual GCash patterns. Menu Grid sits on the dashboard as the primary service shortcut surface — typically Column=4, Row=2 (8 services) on the home screen.
Column=5), 4 row gap, and 6 radius.Column counts tiles across, Row counts tiles down. Values are plain numbers across all 20 variants.SLOT, so each cell is overridable without detaching.| State | iOS | Android | Figma Property | Notes |
|---|---|---|---|---|
| Default | Yes | Yes | Column × Row | Menu Grid is a layout container and has no interaction states of its own. Tap, pressed and disabled behaviour belong to the Service Item child. |
- Variant values are plain numbers. The earlier set used pseudo-numeric strings (
Row="by 4"). The rebuild usesColumn=4, Row=2. String values are the correct and only option here — Figma variant properties cannot be typed as integers — so the prior recommendation to switch to integer props has been withdrawn. C2 · Variant & Property Naming - Service Item is a first-class DS component. Previously flagged as a child of Menu Grid only. It is now published standalone with its own
State/Orientation/Badge/Actionaxes, and Menu Grid instances it rather than redefining tiles. C1 · Layer Structure & Naming - Container metrics are uniform across all 20 variants. Two
Row=5variants previously broke the shared metrics —Column=5, Row=5was 352 wide against 336 everywhere else, andColumn=2, Row=5used 60-tall tiles against 64. Both were corrected in Figma. Every variant is now a 336-wide container at a 4 row gap, with 64-tall tiles atColumn=2and 72-tall tiles atColumn=3–5. C1 · Layer Structure & Naming - Icons come through a slot. Each tile's icon is a Figma
SLOT, not baked artwork, so cells are swappable without detaching the instance. C6 · Asset & Icon Quality
- Document that
Column=2switches the tile to horizontal. AtColumn=2the Service Item child renders atOrientation=Horizontal(158 × 64, icon left of the label);Column=3–5render vertical. Menu Grid exposes no orientation property, so a native lazy grid will not reproduce the switch on its own — it has to be stated in the property mapping. No Figma change required. Docs
EBMenuGrid(items: services, columns: 4, rows: 2) | Role | Element | Token | Value |
|---|---|---|---|
| All variants | Container | — | #FFFFFF |
| All variants | Label | — | #072592 |
| All variants | Row divider (Column 2) | — | #D7E0EF |
iOS — Swift Package Manager
.package(url: "https://github.com/AY-Org/eb-ds-ios", from: "1.0.0")
Android — Gradle (Kotlin DSL)
implementation("com.eastblue.ds:menu-grid:1.0.0")
Import
import EastBlueDS import com.eastblue.ds.menugrid.*
Column and Row are the set’s two variant properties; every cell is a Service Item instance and takes its own properties from that component. The icon slot is hidden in every instance in this set.
| Figma Property | SwiftUI | Compose |
|---|---|---|
| Column — 2, 3, 4, 5 | columns: Int | columns = 4 |
| Row — 1, 2, 3, 4, 5 | rows: Int | rows = 2 |
| Service Item (nested instances) | items: [EBServiceItem.Model] | items = listOf(EBServiceItemModel(…)) |
EBMenuGrid(items: services, columns: 4, rows: 2) EBMenuGrid(
items = services,
columns = 4,
rows = 2
) | Requirement | iOS | Android |
|---|---|---|
| Grid semantics | .accessibilityElement(children: .contain) with a label such as "Services"; each tile is its own button. | LazyVerticalGrid exposes collection info; each tile is a button. |
| Reading order | Left to right, top to bottom — the same order as the layout. | Same order; do not reorder for column count. |
| Tile target | The 77 × 72 and 64 × 72 tiles exceed 44 pt; the 158 × 64 horizontal tile too. | All tiles exceed 48 dp. |
| Overflow | Rows beyond five paginate or scroll; announce the page. | Same — the set builds up to five rows. |
Do
Use Column 4 for the home services grid; 5 for dense category pages.
Don't
Don’t use Column 5 with long labels — the 64 px tile truncates them.
Do
Use Column 2 for two-word services; it switches the tile to Horizontal.
Don't
Don’t mix column counts in one section.
| ID | Criterion | Status | Notes |
|---|---|---|---|
| C1 | Layer Structure & Naming | Ready | Each variant is a flat list of Service Item instances — read on 5973:70256, 5973:70287, 5973:70150. |
| C2 | Variant & Property Naming | Ready | Column and Row with plain numeric values (Figma variant values are strings by nature). |
| C3 | Token Coverage | Not Applicable | No text or fills of its own; every colour belongs to Service Item. |
| C4 | Native Mappability | Ready | Two integers and a list — maps onto EBMenuGrid over the platform grid. |
| C5 | Interaction State Coverage | Not Applicable | States live on the Service Item cells. |
| C6 | Asset & Icon Quality | Ready | Icons come through the Service Item slot; the slot is hidden in this set so the grid ships label-only. |
4 Column × 5 Row = 20 variants
| Column | Rows | Count |
|---|---|---|
| 2 | 1 – 5 · Horizontal tiles 158 × 64 | 5 |
| 3 | 1 – 5 · Vertical tiles 104 × 72 | 5 |
| 4 | 1 – 5 · Vertical tiles 77 × 72 | 5 |
| 5 | 1 – 5 · Vertical tiles 64 × 72 | 5 |
View full Column × Row breakdown (20 rows)
| Column | Row | Node | Dimensions |
|---|---|---|---|
| 2 | 1 | 5973:70192 | 336 × 80 |
| 2 | 2 | 5973:70186 | 336 × 148 |
| 2 | 3 | 5973:70177 | 336 × 216 |
| 2 | 4 | 5973:70150 | 336 × 284 |
| 2 | 5 | 5973:70162 | 336 × 352 |
| 3 | 1 | 5973:70202 | 336 × 88 |
| 3 | 2 | 5973:70195 | 336 × 164 |
| 3 | 3 | 5973:70342 | 336 × 240 |
| 3 | 4 | 5973:70329 | 336 × 316 |
| 3 | 5 | 5973:70313 | 336 × 392 |
| 4 | 1 | 5973:70282 | 336 × 88 |
| 4 | 2 | 5973:70256 | 336 × 164 |
| 4 | 3 | 5973:70227 | 336 × 240 |
| 4 | 4 | 5973:70112 | 336 × 316 |
| 4 | 5 | 5973:70129 | 336 × 392 |
| 5 | 1 | 5973:70276 | 336 × 88 |
| 5 | 2 | 5973:70265 | 336 × 164 |
| 5 | 3 | 5973:70240 | 336 × 240 |
| 5 | 4 | 5973:70206 | 336 × 316 |
| 5 | 5 | 5973:70287 | 336 × 392 |
Column and Row in the panel (count axes never drive cards); the preview now matches the exports — no frame stroke, no icon circles, row dividers at Column 2. Padding, gap, alignment and colour tokens are not readable with the plugin and stay —.Row=5 dimensions corrected — Column=5, Row=5 (5973:70287) narrowed from 352 to 336 to match every sibling, and Column=2, Row=5 (5973:70162) moved from 60-tall to 64-tall tiles, taking the container from 332 to 352. All 20 variants now share the same container width and per-column tile height.
Resolved5973:70111 in GCash Design System · 2026 Working File, replacing 18320:14332 in Sticker Sheets v2. Still 20 variants: 4 Column × 5 Row, all individually verified.
DocumentedColumn=4, Row=2 replaces the earlier Row="by 4" strings. The prior recommendation to move to integer props is withdrawn: Figma variant properties are string-only, so numeric strings are the correct representation.
ResolvedRow=5 variants break the shared metrics — Column=5, Row=5 is 352 wide against 336 everywhere else, and Column=2, Row=5 uses 60-tall tiles against 64.
OpenColumn 2–5 × Row 1–5 with plain numeric labels, the preview renders columns across instead of down, and a readout surfaces the Column=2 → Orientation=Horizontal switch.
DocumentedRow="by 4", Column="by 4". Native takes Int; the string prefix forces parsing.
Opendashboard/service-item/color/active/{icon,label} defined. Other states must be improvised.
Open