Skip to content

Quick reference

Every gg-* attribute the library reads or writes, what reads it, and what shape it expects. One page so you (or an LLM helping you) can scan the whole vocabulary at once.

Data binding

AttributeOnReads / writesNotes
gg-data="<id>"containerreadsRuns query <id>, expects single object. Populates [gg-field] and [gg-switch-field] descendants.
gg-data-list="<id>"containerreadsRuns query <id>, expects array. Clones [gg-list-template] per record.
gg-data-form="<id>"<form> or containerreadsRuns query <id>, expects single object. Pre-fills inputs by name. Array values are ", "-joined into text inputs.
gg-data-on="<key>,..."same as abovereadsRe-runs the query whenever any listed URL param changes. Per-instance override of addQuery(id, fn, { on: [...] }).
gg-field="<dot.path>"descendantwrites textContent (or src on <img>)Set from the parent record. On non-<img> elements, skipped if the path resolves to null/undefined. On <img> the value is written to src instead of textContent, and a null/missing value removes the src attribute (target with img:not([src]) to hide or fall back). On a [name] input inside gg-data-form, overrides the prefill source path while leaving the submitted name unchanged.
gg-field-list="<dot.path>"descendant of gg-datareadsClones [gg-list-template] per item in the array at <dot.path> on the parent record. Same per-row population as gg-data-list, sourced from a sibling record field. Composes recursively.
gg-list-templatechild of gg-data-list or gg-field-listThe template element to clone per record. The original stays in the DOM (hidden via the engine).

Record shape: plain object. Dot-paths are split by . and walked with getPath. Arrays for gg-data or gg-data-form produce a console.warn.

Refreshing after mutations: register a query with addQuery(id, fn, { refreshKeys: ["posts"] }) and call app.invalidate("posts") (or the top-level invalidate import) from any handler that mutates that entity. Every container bound to a subscribed query re-runs. Independent from on.

Reading the record from custom code: every gg-data, gg-data-form, and cloned gg-data-list row sets element.__ggRecord and dispatches a bubbling gg-data-ready CustomEvent (with detail.record) on itself after the query resolves. Web components / React islands listen on the container (e.g. host.closest("form")) to hydrate their own state.

Actions

AttributeOnReads / writesNotes
gg-action="<id>"any elementreadsOn click, runs action <id>. Walks ancestors for a __ggRecord and merges with gg-action-data.
gg-action-data="k1:v1,k2:v2"same elementreadsInline data merged on top of the parent record. Values are strings.
gg-action-data-{name}="<value>"same elementreadsOne attribute per field. Browser lowercases {name}. Wins over the csv form on key collisions.
gg-confirmelement with gg-action or gg-form-actionreadsIf present, calls window.confirm() before firing.
gg-confirm-text="<msg>"samereadsConfirmation message. Defaults to "Are you sure?".

Action handler shape: (context, data, params, helpers) => { ok: boolean, error?: unknown } \| void. Returning { ok: false } triggers onError.

Helpers: helpers.removeItem(predicate) — when the trigger is inside a gg-data-list, removes every clone whose __ggRecord matches the predicate. Fades out if init({ transition }) is configured, otherwise instant. No-ops with a warning when the trigger isn't inside a list.

Form actions

AttributeOnReads / writesNotes
gg-form-action="<id>"<form>readsOverrides submit, runs form action <id> with a FormData snapshot. Also reads gg-action-data / gg-action-data-{name} on the form and passes them as the 4th arg.
gg-form-has-error<form>writtenSet to "true" whenever an error is rendered; removed at the start of each submit. Useful as a CSS hook for the error container.
gg-form-field-invalidinput/select/textareawrittenSet by the engine after a field_errors failure. Cleared on next input.
gg-form-field-error="<name>"elementwritten textContentReceives the message for field <name>.
gg-form-errorelementwritten textContentReceives the top-level error message.
gg-form-error-listcontainerreadsCloning target — see gg-list-template — for rendering one element per field_errors entry.
gg-form-scopecontainerreadsUsed by gg-visible-when to scope its lookups.

Form action handler shape: (context, formData, params, data) => { ok: boolean, error?: unknown, field_errors?: { name, message }[], reset?: boolean } \| void. data is parsed from gg-action-data on the <form>. Successful submits reset the form's inputs by default; return { ok: true, reset: false } to keep values.

URL params

AttributeOnReads / writesNotes
gg-query-set="k1:v1,k2:v2"clickablereadsOn click, sets the listed params. Values support {path} placeholders resolved against the nearest ancestor __ggRecord; a missing path drops just that param.
gg-query-remove="k1,k2"clickablereadsOn click, removes the listed params.
gg-query-bind="<key>"input/select/textareareads + writes URLTwo-way binding between input value and URL param.
gg-query-debounce="<ms>"same inputreadsDebounce ms for gg-query-bind.

Modal param: ?modal=... is reserved — the dialog engine watches it and opens/closes the page's <dialog> element. ?id is removed alongside modal on dismiss.

Switcher

AttributeOnReads / writesNotes
gg-switch-state="<value>"containerreads + writtenChildren with a matching gg-case are shown; others hidden.
gg-switch-field="<dot.path>"container inside gg-datareadsWrites the path's value onto gg-switch-state. Comma-separated paths are joined positionally.
gg-switch-query="<key>"containerreadsMirrors a URL param onto gg-switch-state. Comma-separated keys are joined positionally.
gg-case="<value>"child of a switchreadsVisible when its value matches the parent's gg-switch-state. Empty string = default. Comma = positional AND, | = OR alternatives within a position.
gg-case-defaultchild of a switchreadsPresence-based modifier. Also visible when every segment of gg-switch-state is empty (all keys unset). Combine with gg-case to OR an empty-state fallback into a normal case.
gg-activechild of a switchwrittenEngine adds this presence-only attribute to the currently matching gg-case / gg-case-default child and removes it when the case stops matching.

Visibility

AttributeOnReads / writesNotes
gg-visible-when="name1:value1,..."element inside <form> or [gg-form-scope]readsShown if any condition matches. Fades opacity over 200ms; sets inert + aria-hidden while hidden. For checkboxes use name:checked / name:unchecked (reads .checked directly).

Status

AttributeOnReads / writesNotes
gg-loadingtrigger / form / data containerwritten"loading" or "refreshing" while a handler is in flight; "loaded" after a successful gg-data* query. Buttons / inputs also get the native disabled attribute.
gg-auth<body>written"true" when a user is signed in, "false" otherwise.
gg-auth="true" / "false"any elementreadsHidden via inline display: none when its value doesn't match body[gg-auth].
gg-role="<role>"<body>writtenThe string returned by auth.roleQuery. Removed when no role / signed out.
gg-role="<role>"any elementreadsHidden when the value doesn't match body[gg-role]. Comma-separate for OR, e.g. gg-role="admin,editor".
gg-page-auth="true"<body>readsGates the whole page — redirects to auth.signedOutRedirect if no signed-in user. No-op on *.webflow.io.
gg-page-role="<role>"<body>readsGates the whole page — redirects to auth.unauthorizedRedirect (or signedOutRedirect) if role doesn't match. Comma-separate for OR. No-op on *.webflow.io.

Inbound events

Custom events the library listens for. Dispatch from your own code to drive the engine:

EventWhere to dispatchEffect
gg:dialog:opendocumentOpens the page's <dialog> (without touching the URL).
gg:dialog:closedocumentCloses the page's <dialog> (without touching the URL).
gg:shadow:clickdocument, with detail.target = <Element>Forwarded click for elements inside a shadow root, since shadow DOM swallows bubbling clicks.
webflow:emitdocument, with detail.event = "<ix-event-name>"Bridged into Webflow IX (Webflow.require("ix3").emit).

Outbound events

Custom events the library dispatches. Listen from your own code to react to engine state:

EventWhere dispatchedDetailWhen
gg-data-readythe gg-data / gg-data-form container or cloned gg-data-list row{ record }After the query resolves and __ggRecord has been written. Bubbles, so a single listener on a parent can observe many containers.
gg-app-readydocument{ app }Fired once during init() after the App is built. The same App is also set as window.ggApp. Skip both with init({ expose: false }).

Released under the MIT License.