Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsCommunityBlog
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Authors
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

ProTermsPrivacyRefunds
Back to skills

Frontend V2 Components

ASecurity

Building or modifying components in the RomM v2 frontend (frontend/src/v2/). Use when creating/editing v2 primitives (R* components in src/v2/lib/), shared composites, or feature composites — covers the three-tier model, file/folder conventions, SFC structure, import order, barrels, Storybook requirements, and v2 anti-patterns. Trigger on any work under frontend/src/v2/.

13,119 stars
0 votes
0 copies
1 views
Added 9/20/2026
developmenttypescriptgovuenodeapifrontendbackendperformance

Works with

api

Security Analysis

A100/100

Scanned 9/20/2026

Install to Claude Code

$npx -y skills add rommapp/romm --skill frontend-v2-components --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Frontend V2 Components?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Frontend V2 Components
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/rommapp-frontend-v2-components/badge)](https://www.skillsdirectory.com/skills/rommapp-frontend-v2-components)

More formats (shields.io, HTML) on the badges page.

Download with Pro
Files
SKILL.md
---
name: frontend-v2-components
description: Building or modifying components in the RomM v2 frontend (frontend/src/v2/). Use when creating/editing v2 primitives (R* components in src/v2/lib/), shared composites, or feature composites — covers the three-tier model, file/folder conventions, SFC structure, import order, barrels, Storybook requirements, and v2 anti-patterns. Trigger on any work under frontend/src/v2/.
---

# RomM Frontend v2 — Component Constitution

This governs work inside `frontend/src/v2/`. **v1 is frozen** (`src/views/`, `src/components/`, `src/console/`, `src/layouts/`) — never refactor it; it will be deleted wholesale in a final wave. v2 is gated by `user.ui_settings.uiVersion`.

> Official language for all code, comments, identifiers, `.md`, and commit/PR messages: **English**.

Related skills: `frontend-v2-theming` (tokens/colors), `frontend-v2-input` (focus/gamepad/responsive), `frontend-v2-patterns` (errors/loading/forms/permissions/confirmations), `frontend-i18n`, `review-polish`.

---

## Premises (stable)

1. **v1 is frozen.** Don't touch `src/views/`, `src/components/`, `src/console/`, `src/layouts/`. When coexistence forces a v2 fork of a store/composable/util, annotate the v1 export with `@deprecated` pointing at the v2 replacement.
2. **Three component tiers** (below).
3. **Shared resources are canonical.** Pinia stores, API services, OpenAPI types (`src/__generated__/`), locales, utils — v2 _imports_ them, never forks them. Additive changes to shared resources are allowed; changing a shared store API to work around a v2 call-site issue is not.
4. **TypeScript strict.** Zero `any` (justify with a comment if unavoidable). No `as unknown as ...`; fix the source or define an intermediate type.
5. **Universal substitution.** When an `R*` primitive exists, use it. If it doesn't, create or extend it. Never drop to raw HTML when a primitive applies.
6. **Attribute forwarding contract.** A primitive whose root is polymorphic (`<component :is>`) or that forwards to an inner element uses `defineOptions({ inheritAttrs: false })` + `v-bind="$attrs"` + slot passthrough, so call-site attrs and listeners land on the intended node instead of vanishing silently.
7. **Layout in scoped CSS against tokens.** v2 uses no utility-class framework and no component library: no Tailwind, no Vuetify. Write `display: flex` / `gap: var(--r-space-*)` in the component's own `<style scoped>`. Recurring structure becomes a primitive (`RList`, `RToolbar`, `RCollapsible`, `RVirtualScroller`), not a repeated block of classes.
8. **Accessibility & performance** are requirements: semantic HTML, focus management, contrast, ARIA on icon-only controls; lazy-load heavy views, virtualize large lists, stable `:key` on every `v-for`.

---

## The three tiers

| Tier                  | Path                           | Prefix         | Stores/services/router/emitter/i18n | Story     | Domain knowledge                  |
| --------------------- | ------------------------------ | -------------- | ----------------------------------- | --------- | --------------------------------- |
| **Primitive**         | `src/v2/lib/`                  | `R*` mandatory | **No**                              | Mandatory | None                              |
| **Shared composite**  | `src/v2/components/shared/`    | no prefix      | Yes                                 | Optional  | Cross-feature, no specific domain |
| **Feature composite** | `src/v2/components/<feature>/` | no prefix      | Yes                                 | Optional  | Feature-specific                  |

### A component is a primitive only if all three hold

1. Does not depend on stores, services, router, or emitter.
2. No knowledge of a product domain (ROM, Platform, Collection, User…). `RAvatar` yes, `UserAvatar` no.
3. Its API can be described without naming features — generic props/slots/events.

If any fails: **shared composite** if generic across features, **feature composite** if owned by one feature. Edge cases get raised to the user, not auto-decided. Consumer count never demotes a primitive.

### Primitive boundaries

- **Can use**: tokens, other primitives, Vue, generic composables (`useInput*`, `useFocus*`).
- **Cannot use**: Pinia stores, API services, `emitter`, `router` (a `RouterLink` may be accepted as a prop), `i18n` directly. **No `$t()` in primitives** — text comes via props or slots.
- **Chrome labels** are the exception to "via props": the accessible name
  of a control the primitive renders for itself (a dialog's close button, a
  chip's remove X, a date field's steppers, a stepper's "Step 2 of 5") is
  not caller-supplied content, and a per-instance prop for it has to be
  passed at every call site to have any effect. Read them from
  `useChromeLabels()` (`lib/a11y/chromeLabels.ts`), which the app fills with
  translations via `app.provide` and which falls back to English when
  unprovided. Never hard-code an `aria-label` string (including a bound
  literal like `:aria-label="'Close'"`) or an English prop default in
  `lib/`. A label prop may still exist as a per-instance override,
  defaulting to `undefined` so it resolves through the bundle.

---

## File & folder conventions

- **Primitive**: one per folder — `RFoo/RFoo.vue`, `RFoo/RFoo.stories.ts`, `RFoo/index.ts`, optional `RFoo/types.ts`.
- **Composite**: flat `.vue` if one file suffices; a folder with the same internal structure (no story required) if it has sub-pieces.
- **Barrel**: `src/v2/lib/index.ts` re-exports every primitive — update it when a new primitive ships. Composites are imported directly by path; no barrel. No single-file `index.ts` that just re-exports to shorten a path.

### SFC structure

- `<script setup lang="ts">` always.
- `defineOptions({ inheritAttrs: false })` on every wrapper, paired with `v-bind="$attrs"` and slot passthrough (without the bind, attrs vanish silently).
- Props via `defineProps<Props>()` (interface), never runtime declarations. Emits via `defineEmits<{...}>()`. Slots with payload via `defineSlots<{}>()`.
- Order: `<script setup>` → `<template>` → `<style scoped>`. Unscoped `<style>` (teleport overrides only) goes after the scoped block.

### Import order & aliases

```ts
// 1. External
// 2. v2 primitives
import { RBtn, RDialog } from "@v2/lib";
import { computed, ref } from "vue";
import type { SimpleRom } from "@/__generated__";
// 5. Canonical shared resources
import storeAuth from "@/stores/auth";
// 4. v2 feature siblings
import GameCard from "@/v2/components/GameCard.vue";
// 3. v2 composables / shared
import { useCan } from "@/v2/composables/useCan";
```

- `@v2/lib` — primitives barrel. `@/v2/...` — anything else under v2. `@/...` — canonical shared resources. Never relative paths (`../../foo`) when an alias exists.
- Shared v2 types live in `src/v2/types/`; backend types come from `src/__generated__/`; not `src/types/` (legacy).

### Composables

- `use` prefix; single named export from `composables/useFoo/index.ts`; fully typed args/return; no side effects on module load (init on first call). Creating a v2-only composable when a v1 equivalent exists is allowed.

### Console logging

- `console.error` allowed for production-visible errors. `console.log`/`console.warn` must not ship. `console.debug` is dev-only — remove before PR.

---

## Storybook (mandatory for `/lib`)

- Every primitive ships at least one story with controls and at least one variant per theme.
- A new interactive primitive that warrants gamepad navigation ships a `play()` interaction.
- Modified primitive: existing story must still render and its interactions still pass.
- `npm run test` runs Vitest **and** every `/lib` story's `play()` via `composeStories`. Don't duplicate coverage between Vitest (pure logic) and Storybook `play()` (components).

---

## Anti-patterns (beyond what the premises already say)

1. Don't change shared store APIs to work around a v2 call-site issue. (Fix the call site; the Gallery lesson was calling `romsStore.reset()` from the view, not adding `_fetchSeq` to the store.)
2. Don't drop to inline role checks — always go through `useCan` (see `frontend-v2-patterns`).
3. Don't reinvent a surface — dialog/menu/popover/card all go through their primitive; special cases become a new prop, not a parallel surface.
4. Don't hand-roll a `<form>`; use `RForm`.
5. Don't add backwards-compat shims inside v2: delete removed code; no `// removed`, no renamed-but-unused exports, no deprecated wrappers that just call the new function.
6. Don't write redundant tests; don't touch v1; never `--no-verify` on commits.

**Allowed (often misread):** modifying shared stores/services/utils _additively_; creating v2-only composables; importing from `src/__generated__/`.

---

## Known debt (focused follow-ups)

- **When v1 dies**: move `uiVersion` into `UI_SETTINGS_KEYS`; drop `.r-v2-*` scope classes (tokens move to `:root`); simplify `useUISettings` sync; delete `useGameAnimation`; drop the color-string→tone collapser in `NotificationHost`; remove the Vuetify rule arrays in `stores/users.ts`.

Full reference: `docs/FRONTEND_ARCHITECTURE.md`.

Attribution

rommapprommapp
View sourceMore from rommapp →
SSkills DirectorySkills Directory

Know which skills are safe — weekly.

Best new skills + every skill we flagged as malicious. From the team that scanned 103,619.

Join free

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Know which skills are safe — weekly.

Best new skills + every skill we flagged as malicious. From the team that scanned 103,619.

Join free

Related Skills

Browser Extension Developer

Use this skill when developing or maintaining browser extension code in the `browser/` directory, including Chrome/Firefox/Edge compatibility, content scripts, background scripts, or i18n updates.

284972 votes

Seo Optimizer

SEO optimization with keyword analysis, readability assessment, technical validation, content quality. Use for search rankings, blog posts, content audits, or encountering keyword density, readability scores, meta tags, schema markup errors.

2222 votes

Google Official Seo Guide

Official Google SEO guide covering search optimization, best practices, Search Console, crawling, indexing, and improving website search visibility based on official Google documentation

1862 votes

Tanstack Start

Build a full-stack TanStack Start app on Cloudflare Workers from scratch — SSR, file-based routing, server functions, D1+Drizzle, better-auth, Tailwind v4+shadcn/ui. Use whenever the user mentions TanStack Start, asks to scaffold a full-stack Cloudflare app with SSR, wants an SSR dashboard, or asks for a React 19 + Cloudflare Workers app with file-based routing and server functions — even if they don't name TanStack Start specifically. No template repo — Claude generates every file fresh per ...

10311 votes

Pentest

PTES-aligned adversarial security audit for backend, frontend, and mobile applications. Produces a CVSS-scored Hacker Report with verified PoCs and phased remediation.

5491 votes
View all in development →