Beetle Frontend Best Practices (Verified)
Authoritative, condensed guidance for Svelte 5 + SvelteKit, Tailwind v4, daisyUI v5, Playwright. Sources cross-checked via MCP: Svelte docs, daisyUI repo/docs, Playwright docs.
Svelte 5 + SvelteKit
- Runes: Prefer
$state,$derived,$effectfor state/reactivity. - Event syntax:
onclick={...}works;on:clickremains supported. - Build-time guards: Use
import { building } from '$app/environment'and gate client-only code (if (!building) ...). - Routing & load: Favor server
loadfor SEO and consistent data contracts; use streaming promises for non-critical data. - Accessibility: Keep semantic roles and accessible names for Playwright
getByRolestability.
Tailwind v4 + daisyUI v5
- CSS entry:
@import "tailwindcss"; /* daisyUI via PostCSS plugin (preferred for v4) */ @plugin "daisyui" { themes: light --default, dark --prefersdark; } - Vite: Enable Tailwind plugin
// vite.config.ts import tailwindcss from "@tailwindcss/vite"; import { sveltekit } from "@sveltejs/kit/vite"; export default { plugins: [tailwindcss(), sveltekit()] }; - PostCSS: Optional with Tailwind v4; this repo uses
postcss.config.jswith@tailwindcss/postcssandautoprefixerwhich is fully supported. - Theme control: Use CSS
@plugin "daisyui" { themes: ... }or Tailwind configplugins: [daisyui](either is fine); minimize theme list for bundle size. - A11y: Preserve focus indicators (
:focus-visible), use ARIA roles on custom controls, prefer daisyUI components with roles.
Playwright (E2E)
- Config (CI-friendly)
import { defineConfig } from "@playwright/test"; export default defineConfig({ workers: process.env.CI ? 1 : undefined, retries: process.env.CI ? 2 : 0, use: { trace: "on-first-retry", video: "on-first-retry", screenshot: "only-on-failure", // Decide per suite: // serviceWorkers: 'block' | 'allow' }, }); - Locators: Prefer
page.getByRole('button', { name: 'Play' })andexpect(locator).toHaveAccessibleName('Play'). - Auth: Use worker-scoped
storageStatefixtures to authenticate once per worker. - Network: Use
route.fulfill/browserContext.routefor API mocking; isolate third-party calls. - Tracing: Keep traces/videos for flakies only (
on-first-retry).
UI Patterns
- Theme picker: Use daisyUI
theme-controllerordata-themeon:root; store last theme inlocalStorage. - Dropdowns/menus: Use daisyUI
Keep<div class="dropdown"> <div tabindex="0" role="button">Open</div> <ul tabindex="-1" class="dropdown-content menu"></ul> </div>tabindex+rolefor keyboard support. - Modals: Prefer
<dialog class="modal">patterns; ensure focus trap and close actions.
Data & Performance
- Load contracts: Normalize API shapes; include error states from server
load. - Selective loading: Use streaming promises for non-critical data.
- Images/fonts: Use SvelteKit guidance; avoid waterfalls; preload fonts prudently.
Service Workers
- Cache busting: Update cache version on deploy; provide clear cache-clear instructions (see
guides/CACHE_CLEAR_INSTRUCTIONS.md). - Testing: In Playwright, set
serviceWorkersper-suite and optionally wait for activation withcontext.waitForEvent('serviceworker').
— Sources: SvelteKit docs (routing/build/performance/testing), daisyUI v5 docs (themes/components/config), Playwright docs (best practices, retries, tracing, service workers).