softr-vibe-coding 2.13.3 → 2.13.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/README.md +8 -5
- package/SKILL.md +77 -10
- package/package.json +1 -1
- package/references/anti-patterns.md +12 -7
- package/references/browser-checks.md +156 -1
- package/references/common-patterns.md +223 -1
- package/references/dembrandt.md +7 -2
- package/references/native-chrome-styling.md +163 -14
- package/references/quick-reference.md +38 -0
- package/references/searchable-dropdown.md +28 -1
- package/references/static-blocks.md +7 -4
- package/ui-ux-guidelines.md +38 -4
|
@@ -151,6 +151,32 @@ the hidden part); a picker at the bottom of a dialog body opens up, inside the d
|
|
|
151
151
|
row at the window's bottom edge opens up, as before. All four, plus a scroller outside the
|
|
152
152
|
shadow root, checked in Chromium on 2026-09-30 on a test page — not yet in a deployed block.
|
|
153
153
|
|
|
154
|
+
**On app pages with Softr navigation, the strip doesn't reach the window's edges either.**
|
|
155
|
+
Softr's bars sit over the page, outside the block: from a 768px window, a 56px sticky top bar;
|
|
156
|
+
below it, a sticky tab bar at the bottom, 57px as rendered (Softr's variable says 55px; both bars
|
|
157
|
+
z-index 800, measured live 2026-10-05). The walk above starts the strip at `0` and
|
|
158
|
+
`window.innerHeight`, so a trigger just under the top bar
|
|
159
|
+
can open its menu up and under the bar, and on a phone a menu can open down behind the tab bar.
|
|
160
|
+
That clash is inferred from the measurements, not seen. Start the strip inside the bars (an
|
|
161
|
+
untested variant):
|
|
162
|
+
|
|
163
|
+
```jsx
|
|
164
|
+
var SOFTR_TOP_BAR = 56; // Softr's sticky top bar, window 768px and up
|
|
165
|
+
var SOFTR_TAB_BAR = 57; // Softr's phone tab bar, window below 768px: measured 57px; its variable says 55px
|
|
166
|
+
|
|
167
|
+
function comboClipBox(node) {
|
|
168
|
+
var phone = window.innerWidth < 768; // Softr's own switch: 767px = tab bar, 768px = top bar
|
|
169
|
+
var top = phone ? 0 : SOFTR_TOP_BAR;
|
|
170
|
+
var bottom = window.innerHeight - (phone ? SOFTR_TAB_BAR : 0);
|
|
171
|
+
// … the ancestor walk, unchanged
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
On a page without Softr navigation (log in, a landing page) the top offset only makes the
|
|
176
|
+
panel open upward a little less readily. The same bar heights apply to any other room check
|
|
177
|
+
or window scroll in a block:
|
|
178
|
+
[common-patterns.md → Clear Softr's sticky bars](common-patterns.md#clear-softrs-sticky-bars).
|
|
179
|
+
|
|
154
180
|
Rule 2 does not rescue a clipped cell. The cell is the height of its row, so neither side has
|
|
155
181
|
room, the list falls to its 120px floor and is clipped anyway. Rule 1 is not optional.
|
|
156
182
|
|
|
@@ -345,7 +371,8 @@ Everything else — the trigger, the card, the rows — stays flat.
|
|
|
345
371
|
- [ ] No overflow-clipping class (`overflow-hidden`, `overflow-*-auto`, `truncate`,
|
|
346
372
|
`line-clamp-*`) between the Combo and the scroller it belongs to; an over-wide chip
|
|
347
373
|
bounded at the chip (`min-w-0 truncate`)
|
|
348
|
-
- [ ] Drop-up and list `maxHeight` measured against the clipping ancestors, not the window
|
|
374
|
+
- [ ] Drop-up and list `maxHeight` measured against the clipping ancestors, not the window, and
|
|
375
|
+
on app pages inside Softr's top bar and phone tab bar
|
|
349
376
|
- [ ] Keyboard: ↑ ↓ Enter Esc Tab; the active row kept visible by scrolling the list only
|
|
350
377
|
(never `scrollIntoView`), and the search box focused with `preventScroll`
|
|
351
378
|
- [ ] `aria-haspopup="listbox"`, `aria-expanded`, `role="listbox"` / `role="option"`,
|
|
@@ -37,9 +37,11 @@ SKILL.md's Premium Visual Baseline (gradient wrapper, icon-in-rounded-square hea
|
|
|
37
37
|
|
|
38
38
|
**`container`/`content` wrappers are optional platform behavior, not platform-enforced.** Per the official developer guide: "By default, block occupies full width of the page but special classes - `container` and `content` are **available** to constrain the width [of content to match app's max width settings]" (emphasis added). The wrappers remain the strong default for app/content blocks that sit next to native blocks (width consistency — that's their whole purpose). Static marketing blocks legitimately skip them so backgrounds, images, and decorative shapes run edge-to-edge.
|
|
39
39
|
|
|
40
|
+
App pages are the other full-bleed case. Beside Softr's sidebar / top-bar navigation, inside a frame the app's header code paints, an app block drops the wrappers too — but it also paints no background and lays out by its own width with container queries. That case has its own rules: [SKILL.md → App pages beside Softr navigation](../SKILL.md#app-pages-beside-softr-navigation).
|
|
41
|
+
|
|
40
42
|
When you go full-bleed:
|
|
41
43
|
|
|
42
|
-
- **Own your horizontal gutters** — the responsive padding ramp `px-6 md:px-12 lg:px-16` on the content container is the Studio-verified shape.
|
|
44
|
+
- **Own your horizontal gutters** — the responsive padding ramp `px-6 md:px-12 lg:px-16` on the content container is the Studio-verified shape. It steps on the WINDOW width, which suits a full-width marketing page and not a block beside Softr's sidebar: there the block is 57–360px narrower than the window (744px wide at a 1024px window with the sidebar open, measured 2026-10-05), so use the container-query shell from the app-page section instead.
|
|
43
45
|
- **Own your inner max-widths** — constrain the copy column yourself (`lg:max-w-[46%]`, `max-w-[430px]` on body text).
|
|
44
46
|
- **`overflow-hidden` on the block root** if decorative shapes offset off-canvas (prevents horizontal scroll).
|
|
45
47
|
- **Record the choice** in the placement comment so future edits and reviews know it's deliberate:
|
|
@@ -77,7 +79,7 @@ The caveat set — state these in any block that ships its own header:
|
|
|
77
79
|
|
|
78
80
|
1. **Per-page only.** The header exists solely on pages containing this block. Every page of a multi-page site needs either this block or the native header, or navigation disappears.
|
|
79
81
|
2. **No auth-aware nav logic.** You forfeit Softr's account menu and user-group-gated items — nav items are plain `<NavigationAction>`s. Fine for public landing pages; wrong for logged-in app pages. For the login CTA, use the auth-aware swap (`useCurrentUser()` → "Sign in" vs "Dashboard") from [common-patterns.md](common-patterns.md#auth-aware-header-cta).
|
|
80
|
-
3. **Don't ship both headers on one page.** The z-index outcome against a visible native `#topbar-root` (sticky, main document) is untested — hide the native header on this page, or don't use the pattern.
|
|
82
|
+
3. **Don't ship both headers on one page.** The z-index outcome against a visible native `#topbar-root` (sticky, z-index 800 in the main document — measured 2026-10-05) is untested — hide the native header on this page, or don't use the pattern.
|
|
81
83
|
4. **Keep transforms/filters off the header's ancestors.** `position: fixed` anchors to the viewport ONLY while no ancestor establishes a containing block — a `transform`, `filter`, `perspective`, or `will-change` on the block root (e.g. an entrance animation) silently converts the "fixed" header to absolute and lets `overflow-hidden` clip it. Leaf-element transforms (`hover:-translate-y-[1px]` on buttons) are fine. Verify in the **published app**, not just the Studio canvas.
|
|
82
84
|
5. **Mobile nav is mandatory.** `hidden md:flex` on the nav with no fallback means nav items simply don't exist on phones (Studio AI ships exactly this bug). Pair the pattern with a shadcn `Sheet`-based mobile menu (hamburger → drawer listing the same `navItems` array) — the component is on the platform roster.
|
|
83
85
|
6. **Landmark hygiene.** Shadow DOM does NOT hide landmarks from assistive tech, and Softr's native chrome uses semantic elements. On a page with native chrome visible, a block's own `<header>`/`<main>` creates duplicate banner/main landmarks — use plain `<div>`s there. Reserve `<header>`/`<main>` for pages where the native chrome is hidden and the block genuinely IS the page chrome.
|
|
@@ -89,8 +91,9 @@ The wider decision (restyle native vs replace globally vs block-owned) is laid o
|
|
|
89
91
|
Heroes pair with same-page sections via hash links (nav "Capabilities" → `#capabilities` further down).
|
|
90
92
|
|
|
91
93
|
- **Write anchor destinations RELATIVE**, per Hard Constraint 20: `/#capabilities` or `/page#section`. A Studio-generated hero shipped its CTA configured as the absolute self-domain form (`https://<app>.softr.app/#capabilities`, observed in the Settings pane 2026-08-31) — rewrite that form; hardcoded domains break on custom-domain publish and between staging/production.
|
|
92
|
-
- **A URL fragment cannot target an element inside a Vibe block's shadow root** — fragment lookup stops at the shadow boundary (same family as the documented `getElementById` anti-pattern). Anchors must target something in the main document: the block/section host. Softr has a native anchor-link mechanism targeting blocks — **verify live which fragment a Vibe Coding block answers to** before promising exact syntax to a user.
|
|
93
|
-
- **
|
|
94
|
+
- **A URL fragment cannot target an element inside a Vibe block's shadow root** — fragment lookup stops at the shadow boundary (same family as the documented `getElementById` anti-pattern). Anchors must target something in the main document: the block/section host. Softr has a native anchor-link mechanism targeting blocks — **verify live which fragment a Vibe Coding block answers to** before promising exact syntax to a user. (Seen 2026-10-05: a Vibe block's outer wrapper in the main document is `#main-content > div[data-block="vibe-coding-…"]` with a page-assigned id such as `ai1`; whether a fragment for that id jumps to it is untested.)
|
|
95
|
+
- **The sticky top bar is already cleared for a jump to a block's outer wrapper.** Softr's page CSS gives that wrapper (`#main-content > div[data-block]`, the element with the page-assigned id, previous bullet) `#main-content [data-block] { scroll-margin-top: var(--sticky-nav-height, 0px) }`, so a fragment jump to it should stop below the 56px top bar (rule read from the page CSS 2026-10-05; the jump itself untested). The Vibe host two levels inside it carries no `data-block`, and nothing does that for content inside the block.
|
|
96
|
+
- **In-block scrolling** (scroll to a section inside the same block) uses refs + `scrollIntoView` with the `setTimeout(fn, 0)` rule (Hard Constraint 17), not fragments. It must add the top-bar offset itself, or the target lands under the sticky bar — for example `scroll-margin-top: calc(var(--nav-height, 0px) + 16px)` on the target (standard CSS, untested in a block). See [common-patterns.md → Clear Softr's sticky bars](common-patterns.md#clear-softrs-sticky-bars).
|
|
94
97
|
|
|
95
98
|
## Harvesting Studio-AI marketing blocks
|
|
96
99
|
|
package/ui-ux-guidelines.md
CHANGED
|
@@ -236,6 +236,7 @@ All spacing uses **multiples of 4px**. The critical step that pure 8pt systems m
|
|
|
236
236
|
|
|
237
237
|
### Depth and Elevation:
|
|
238
238
|
- Use semantic z-index levels: dropdown (100) > sticky (200) > modal-backdrop (300) > modal (400) > toast (500) > tooltip (600).
|
|
239
|
+
- **That scale orders a block's own layers. Softr's bars sit outside it** (sticky, z-index 800, in the main document; measured live 2026-10-05): clear them with an offset, don't try to outrank them. See [§26](#26-finishing-touches) and [common-patterns.md → Clear Softr's sticky bars](references/common-patterns.md#clear-softrs-sticky-bars).
|
|
239
240
|
- Shadows should be subtle. If you can clearly see it, it is probably too strong.
|
|
240
241
|
|
|
241
242
|
---
|
|
@@ -401,6 +402,16 @@ Vestibular disorders affect ~35% of adults over 40. Always respect `prefers-redu
|
|
|
401
402
|
links them -- in a Tailwind + inline-token codebase the colour is literally written twice.
|
|
402
403
|
- **Skeletons repeat page chrome too.** If the page has a back button, breadcrumb or title above the
|
|
403
404
|
content, the skeleton needs those at the SAME offsets, or the chrome jumps when the record arrives.
|
|
405
|
+
- **Under container queries, set skeleton line counts and heights at BLOCK widths, with the real fonts.**
|
|
406
|
+
The block's padding and column count step with its own width, and both move where text wraps: a note
|
|
407
|
+
that fits on one line in a 600px two-column block wraps in a 900px four-column block, because its cell
|
|
408
|
+
got narrower. A skeleton keyed to a guessed threshold jumps when the data lands. Measure where the real
|
|
409
|
+
text wraps across a sweep of block widths, then key the skeleton heights to those widths
|
|
410
|
+
(`h-[39px] @min-[387px]:h-[19.5px]`). (2026-10-05: after a padding change, the figure labels fit on one
|
|
411
|
+
line from a 387px block, but the skeleton, keyed at `@min-[30rem]`, kept two-line bars, so it was 39px
|
|
412
|
+
too tall at 390px. In the four-column layout (about 832–1170px) the notes wrap to two lines, but the
|
|
413
|
+
skeleton reserved one, so the page jumped 19.25px. The fix came from a headless sweep of 300 to 1400px
|
|
414
|
+
block widths with the real fonts. It shipped, but was not visually re-checked after the push.)
|
|
404
415
|
|
|
405
416
|
### Perceived Performance:
|
|
406
417
|
- **Optimistic UI**: Update the interface immediately, handle failures gracefully. Use for low-stakes actions (likes, filters); avoid for payments or destructive operations.
|
|
@@ -518,7 +529,7 @@ Users always need to know: *Where am I? Where can I go? How do I get back?*
|
|
|
518
529
|
|
|
519
530
|
### Mobile adaptation:
|
|
520
531
|
- Transform table rows into **stacked card layouts** on small screens.
|
|
521
|
-
- `hidden md:block` on the table, `block md:hidden` on mobile cards.
|
|
532
|
+
- `hidden md:block` on the table, `block md:hidden` on mobile cards. That is a window breakpoint: beside Softr's sidebar navigation, key the swap to the block's width with container variants instead (`hidden @min-[48rem]:block` / `@min-[48rem]:hidden`, under an `@container` wrapper; see [§21](#21-mobile-first-responsive-design)).
|
|
522
533
|
- Never require horizontal scrolling for important data.
|
|
523
534
|
|
|
524
535
|
---
|
|
@@ -569,12 +580,12 @@ Avoid the "hero metric layout template" — big number, small label, supporting
|
|
|
569
580
|
## 21. Mobile-First Responsive Design
|
|
570
581
|
|
|
571
582
|
### Rules:
|
|
572
|
-
- **Start with `flex-col`**, stack to `md:flex-row` or grid layouts at larger screens.
|
|
583
|
+
- **Start with `flex-col`**, stack to `md:flex-row` or grid layouts at larger screens. Beside Softr's sidebar navigation, switch on the block's width instead (`@min-[48rem]:flex-row` under an `@container` wrapper). See [Breakpoint strategy](#breakpoint-strategy) below.
|
|
573
584
|
- **No horizontal overflow.** Use `overflow-x-hidden` as safety net.
|
|
574
585
|
- **Touch targets: 44px minimum.**
|
|
575
586
|
- **Hover states are desktop-only.** Never depend on `:hover` for essential actions.
|
|
576
587
|
- Form fields: `w-full` on mobile.
|
|
577
|
-
- Navigation: collapse to hamburger or bottom nav on small screens.
|
|
588
|
+
- Navigation: collapse to hamburger or bottom nav on small screens. This applies only to navigation a block draws itself. In apps with Softr's sidebar / top-bar navigation layout, Softr switches its own navigation to a phone tab bar below a 768px window: 767px gives the tab bar, 768px gives the top bar and sidebar (verified live 2026-10-05; a top-bar-only app was not checked). On a page with Softr navigation, don't build a second one into the block.
|
|
578
589
|
|
|
579
590
|
### Art-directed responsive images:
|
|
580
591
|
A settings hook returns a plain value, so one `useImageSetting` may safely feed **two sibling `<img>` renders** with opposite visibility classes — desktop: absolute-positioned, masked, cropped via arbitrary `object-[x%_y%]`; mobile: in-flow full-bleed (`hidden lg:block` / `lg:hidden`, same mechanism as the table→cards swap in §18). The builder still edits ONE image in the Settings pane. To bleed the mobile render edge-to-edge against the wrapper's own horizontal padding, use matching negative margins (`-mx-6` against `px-6`, `md:-mx-12` against `md:px-12`).
|
|
@@ -584,6 +595,26 @@ A settings hook returns a plain value, so one `useImageSetting` may safely feed
|
|
|
584
595
|
Mobile first: default -> sm (640px) -> md (768px) -> lg (1024px) -> xl (1280px)
|
|
585
596
|
```
|
|
586
597
|
|
|
598
|
+
Those are **window** breakpoints. They are right when the block spans the window: marketing pages, and pages with no sidebar.
|
|
599
|
+
|
|
600
|
+
**Beside Softr's sidebar navigation, size by the block's width, not the window's.** The sidebar takes 280px by default, 57px collapsed, and anywhere from 200 to 360px when dragged, so the window over-reports the block's width by that much. At a 768px window with the sidebar open, the block gets 488px. At 1024px it gets 744px, yet `lg:` fires: in a real dashboard that squeezed a 5-column chart row and cut off its labels (verified live 2026-10-05). Use container queries:
|
|
601
|
+
|
|
602
|
+
```jsx
|
|
603
|
+
<div className="@container"> {/* the block's outer wrapper: the container */}
|
|
604
|
+
<div className="grid grid-cols-2 gap-4 @min-[52rem]:grid-cols-4"> {/* children use @min-[…] */}
|
|
605
|
+
…
|
|
606
|
+
</div>
|
|
607
|
+
</div>
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
- `@container` on a wrapper, `@min-[NNrem]:` variants on what is inside it. A query resolves against the nearest **ancestor** container, never the element itself, so the two cannot sit on the same element.
|
|
611
|
+
- Softr's Tailwind (4.1.13) compiles the container variants (verified live 2026-10-05).
|
|
612
|
+
- Nest a second `@container` on a pane (a detail panel beside a list) so the pane's insides follow the pane, not the page.
|
|
613
|
+
- Derive a threshold from the parts it has to fit. For example, list and detail go side by side from an 860px block: a 340px list, a 20px gap, at least 440px of detail, plus padding.
|
|
614
|
+
- When a decision can't be made in CSS (render a different tree, thin out chart ticks), measure the block in JS: [common-patterns.md → Measure the block, not the window](references/common-patterns.md#measure-the-block-not-the-window).
|
|
615
|
+
|
|
616
|
+
The page shell for these pages (full-bleed, no container/content wrappers, gutters set by container query) is in [SKILL.md → App pages beside Softr navigation](SKILL.md#app-pages-beside-softr-navigation).
|
|
617
|
+
|
|
587
618
|
### Beyond screen size:
|
|
588
619
|
Consider pointer and hover capabilities, not just viewport width. A laptop with touchscreen and a tablet with keyboard both exist. Touch devices need larger targets and always-visible controls.
|
|
589
620
|
|
|
@@ -720,7 +751,7 @@ Actively check for and reject these fingerprints of generic AI-generated interfa
|
|
|
720
751
|
- **Badge counts:** Show filtered item count ("3 active projects")
|
|
721
752
|
- **Relative timestamps:** "2 hours ago" via `date-fns/formatDistanceToNow`
|
|
722
753
|
- **Truncate long text** with `truncate` or `line-clamp-2`, full value in `Tooltip`
|
|
723
|
-
- **Sticky headers** for long tables
|
|
754
|
+
- **Sticky headers** for long tables. When the header sticks to the page scroll (not to the table's own scroller) on a page with Softr's top bar, offset it by the bar: `top: calc(var(--nav-height, 0px) + 16px)`, not `top-0`/`top-4`. Softr's `#topbar-root` is sticky at top 0, z-index 800, 56px tall, so anything sticky at the window's top slides under it. A list pane fixed this way measured top 72px (verified live 2026-10-05). See [common-patterns.md → Clear Softr's sticky bars](references/common-patterns.md#clear-softrs-sticky-bars).
|
|
724
755
|
- **Never render an affordance you have not wired.** A grip glyph that does not drag, a chevron that does not sort, a card that looks clickable and is not — the signifier IS the promise, and an unfulfilled one reads as a broken feature, not a missing one. Either wire it or delete it. (Observed 2026-09-09: a `GripVertical` shipped as decoration on every row of a reorderable list; users reported the list as "can't be reordered", not as "missing drag".)
|
|
725
756
|
- **A control that is disabled by default is indistinguishable from a broken one.** If the only explanation lives in a `title` tooltip, nobody reads it — they file a bug. When a control depends on a mode the user has not chosen yet, prefer making the action *switch the mode and proceed* over greying it out. Disable only for genuine impossibility (permissions, first row can't move up), and when you do, say why in visible text rather than on hover. (Same 2026-09-09 report: reorder arrows were disabled until you switched the sort to Manual, which nothing on screen told you.)
|
|
726
757
|
|
|
@@ -743,6 +774,8 @@ Actively check for and reject these fingerprints of generic AI-generated interfa
|
|
|
743
774
|
| Loading data | `Skeleton` matching content structure |
|
|
744
775
|
| Empty collection | Icon + heading + explanation + CTA |
|
|
745
776
|
| Error state | Icon + message + retry button |
|
|
777
|
+
| Layout beside Softr's sidebar | `@container` wrapper + `@min-[NNrem]:` variants, never window breakpoints ([§21](#21-mobile-first-responsive-design)) |
|
|
778
|
+
| Sticky element on an app page | `top: calc(var(--nav-height, 0px) + 16px)` ([common-patterns.md](references/common-patterns.md#clear-softrs-sticky-bars)) |
|
|
746
779
|
|
|
747
780
|
## Appendix B: Motion and Spacing Tokens
|
|
748
781
|
|
|
@@ -763,6 +796,7 @@ Actively check for and reject these fingerprints of generic AI-generated interfa
|
|
|
763
796
|
--z-modal: 400;
|
|
764
797
|
--z-toast: 500;
|
|
765
798
|
--z-tooltip: 600;
|
|
799
|
+
/* Softr's top bar and phone tab bar: sticky, z-index 800, outside the block. Clear them, don't outrank them (§7). */
|
|
766
800
|
```
|
|
767
801
|
|
|
768
802
|
## Appendix C: Design Brief Template
|