Skip to content

v1.54.0

Latest

Choose a tag to compare

@mmollay mmollay released this 27 Aug 14:39
· 209 commits to main since this release

GridKit has moved a long way since the last release was published here in March.
The tags were pushed, the release notes were not — this one closes that gap.
The complete history of all 36 versions is in CHANGELOG.md.

Install

composer require mmollay/gridkit

What GridKit is: PHP components for admin dashboards — table, form, modal,
sidebar, header and eleven more. No build step, no dependencies, no JavaScript
framework. One CSS file and one JS file. Live demo.

New in this release: an installable agent skill. cp -r skill ~/.claude/skills/gridkit,
or point any assistant at https://gridkit.ssi.at/skill/.


Everything since 1.50.0, in one release. The full history is in
CHANGELOG.md.

[1.54.0] - 2026-08-27

Three ways to hand the API to an assistant, where there was one.

Added — the installable skill

skill/ is GRIDKIT_SKILL.md split so an assistant reads the rules first —
which calls print and which return a string, how Layout::asset() resolves,
which components drop your filters unless told to keep them — and fetches one
reference when it needs one. Sixty-one kilobytes is a lot of context to spend on
a question about one method.

skill/SKILL.md                203 lines   the rules, with frontmatter
skill/reference/components.md 1044 lines  every component, every option
skill/reference/javascript.md  121 lines  GK.*, live tables, global search
skill/reference/css.md          30 lines  class names, utility classes

Generated by ci/build-skill.sh, never edited by hand: one source, two shapes,
and a test that fails if they drift. The split is lossless — all 39 headings,
all 46 runnable examples, all 128 public methods.

Install: cp -r skill ~/.claude/skills/gridkit.

Added — a stable address, and llms.txt

https://gridkit.ssi.at/skill serves the whole document as text/markdown,
with CORS open so an assistant can fetch it. llms.txt at the site root points
there, which is the convention a site uses to tell a model what it needs to
know. Both through .htaccess, which also stops serving composer.json,
tests/ and ci/ — none of which are part of the site.

Fixed — a commit that would have blocked every push

The 1.53.0 commit carried .github/workflows/ci.yml. The token this repository
is pushed with has no workflow scope, so that commit could never leave the
machine and everything after it was stuck behind it — the local branch sat one
ahead of the remote with no error to explain why. Recommitted without it; the
workflow still ships as ci/github-actions.yml.

2,199 assertions.


[1.53.0] - 2026-08-27

Two small things in the table, both of which had been quietly costing
readability. Neither changes any markup — every existing page gets them.

Changed — digits line up

font-variant-numeric: tabular-nums on table cells. Proportional digits
are narrower for a 1 than for a 0, so a column of amounts or dates wanders a
little in every row. In prose that is right; in a column of figures it is
noise. Only digits are affected — text in the same cell keeps its normal
spacing.

Visible immediately in any table with a date, a count or an amount.

Changed — the header reads as the header

The header rule is one step darker than the row rules
(--gk-surface-container-highest instead of --gk-outline-variant).

1.44.0 removed the grey bar behind thead for good reasons: caps, size and
weight already announce a header, and a filled bar says the same thing a second
time. But the line that was left to do the separating alone was the same
hairline that separates the rows — so it separated nothing in particular, and
in a long table the head floated among the rows.

One step darker is enough. The token carries its own dark-mode value, so this
holds in both modes without an exception rule.

Unchanged on purpose

The pill radius, the row padding and the zebra decision stay as they are. They
are taste, not craft, and taste belongs in a theme — not in a patch release
that every consuming system picks up without asking.


[1.52.0] - 2026-08-27

Packagist was updated, so composer require mmollay/gridkit finally installs
the current version rather than v1.4.0 from March. That made a test possible
that had never been run: download the archive Packagist really serves, unpack
it, write a page against it the way the README says, and use it.

It found a bug in about two minutes.

Fixed — a delete button that stopped asking

data-gk-confirm was not emitted by the client re-render. The server puts
it on the button; the browser rebuilds that button on every sort, search and
page change of a setData() table, and rebuilt it without the attribute. So a
delete button asked for confirmation once, on first load, and then never again
— the click went straight through to gk:rowaction.

Measured in a browser against the real package:

data-gk-confirm click asks?
on load "Delete this entry?" yes
after a sort missing no

1.32.0 fixed exactly this on the server side, where the delete button in the
README's own example was deleting without asking. The client path kept it.

The re-render now emits it, using js.confirm_delete_row — the single-row
wording that matches table.confirm_delete, not the bulk "Really delete
entries?" that js.confirm_delete carries.

Verified — the whole thing, from Packagist

Not a simulation this time. The zipball Packagist points at, unpacked into
vendor/mmollay/gridkit/, with a page written from the README: sidebar, fixed
header, stat cards with trends, a searchable sortable table with row actions and
client-side paging, in English and German.

All three assets 200. No PHP notice, no console error. Page two slices in the
browser with no network request. Search filters. The status labels colour
correctly. The delete button announces itself as "Delete" / "Löschen".

2,184 assertions.


[1.51.0] - 2026-08-27

Round twenty-three asked whether twenty-three rounds of edits still hold
together, and pointed five auditors at the demo — the shop window, audited for
its claims in 1.44.0 but never for its markup.

Fixed — nine of eleven demo sections were under the sidebar

One extra </div> closed .gk-with-sidebar right after the Form section.
Everything after it — Cards, Layout, Navigation, Search, Feedback, UI,
Examples, Tooltip, Changelog — was a child of <body>, so the left 260px of
each sat beneath the fixed sidebar. Not merely clipped: elementFromPoint(150, 300) returned a sidebar link, so that strip swallowed clicks meant for the
demo's own controls.

CHANGELOG 1.36.0 describes this exact failure as the thing the wrapper
prevents. The demo has had it ever since.

It survived because counting tags cannot see it: the stray close consumes the
wrapper, which demotes the intended closer at the end of the file to a trailing
stray, and browsers discard that silently. The div count nets to zero. Only an
ancestry assertion catches it, and there is one now.

Fixed — the demo at 390px

  • Three fixed-column grids gave each child 101px on a phone — the "Sizes"
    sample rendered three tables at 101px each, labels printing over values. They
    wrap now.

  • An invisible tooltip widened the page by 58px.
    [data-gk-tooltip]::after is position: absolute with white-space: nowrap
    and opacity: 0 — laid out while invisible, so a long one pushes the
    document wider with nothing visible anywhere near the edge. That is why
    several mobile passes went straight past it. The left and right variants
    reach out with left/right: 100% and added their own. On a narrow screen
    the text now wraps under a cap and the side variants move above their
    element; the desktop look is untouched.

    The first attempt at that fix did nothing, because the override sat before
    the rules it meant to beat and lost on source order. So did the first version
    of the test for it, which compared the block against itself — the block
    contains the very selector it was searching for.

Added

  • A test that every [data-section] in the rendered demo has .gk-with-sidebar
    as an ancestor. Checked against the stray tag put back: nine failures.
  • A test that the narrow-screen tooltip cap exists and comes after the rules
    it overrides.
  • A Composer install, end to end. The README has offered
    composer require mmollay/gridkit from the start and nobody had ever run one.
    The test builds the archive Packagist would ship, lays it out as Composer
    would, generates the autoloader Composer would generate, and checks that the
    documented asset path resolves to the file that is really there — the one
    thing a plain clone never exercises. It passes.

2,174 assertions, on three interpreters.