Files
crewli/dev-docs/PRIMEVUE_COMPONENTS.md
bert.hausmans 637d77b327 docs(plan-3): close out Plan 3 — BACKLOG entries, RFC status, primitives registry, tooling conventions
- BACKLOG: add 3 spawned follow-ups (EnergyDots NaN, DraggableBlock pointercancel, AD-3 Menubar a11y)
- RFC-WS-GUI-REDESIGN-CREWLI-STARTER: mark Plan 3 complete with commit refs + DoD ledger
- PRIMEVUE_COMPONENTS: v2 primitives registry (8 components), statusSeverity SoT, Menubar-wrap pattern
- ARCH-TESTING: mount-helper type convention (Plan 3 codified, Plan 4 carry-over)
- FRONTEND-TOOLING: scoped lint invocation note (DoD #13 root cause)
- AppDialog.stories.ts: rename title to 'Shared/AppDialog' for sibling consistency
2026-05-19 01:41:19 +02:00

30 KiB
Raw Permalink Blame History

PRIMEVUE_COMPONENTS — PrimeVue Component Conventions for Crewli

Authoritative reference for PrimeVue component selection, theming, forms, and DataTable conventions in the Crewli SPA. Read this before adding or migrating a UI component during F4 of RFC-WS-FRONTEND-PRIMEVUE. This document encodes Crewli-specific conventions; for component reference (props, slots, events) cross-reference https://primevue.org/.

Status: Foundation (F2). Refined incrementally by F4 sub-packages as real migration experience surfaces gaps.

GUI redesign: the page-migration phase is governed by dev-docs/RFC-WS-GUI-REDESIGN-CREWLI-STARTER.md (supersedes F4aF4d). This component reference still applies to all v2 work.

Aligned to: PrimeVue 4.5.x with the Aura preset and @primevue/forms. PrimeVue is installed in F3; F2 documents intent only. Replaces: VUEXY_COMPONENTS.md (now a deprecation stub; deletion in F6).


v2 primitives registry (Plan 3)

Landed by Plan 3 of RFC-WS-GUI-REDESIGN-CREWLI-STARTER.md (commits 537ec098..0b19e785 on main). All eight live under apps/app/src/components-v2/shared/; each has a co-located <Name>.stories.ts (Storybook title Shared/<Name>) and a co-located __tests__/<Name>.spec.ts. PrimeVue-first per AD-G3; scoped CSS only where the spec justifies it (EnergyDots/EnergyPicker §8, DraggableBlock §7.1).

Component Purpose Props (summary)
StatusTag PrimeVue Tag whose severity is resolved from a status string via the SoT map (never inlined) status, label?, dot?
StatCard KPI tile (PrimeVue Card + Icon + optional trend) — replaces v1 AppKpiCard icon, label, value, trend?, trendDir?
PageHead Thin Tailwind flex page header (title / sub / #actions slot); no PrimeVue dependency title, sub? (+ #actions slot)
StateBlock Mandatory loading / error / empty three-state wrapper + success passthrough state, errorMessage?, emptyMessage?, actionLabel?, retryLabel? (emits retry, action)
TagsInput Multi-tag input — re-implementation on PrimeVue AutoComplete (multiple + typeahead); lowercase-dedupe, comma/Enter split, 5-suggestion cap modelValue?: string[], suggestions?: string[], placeholder?
EnergyDots Read-only 5-dot energy meter (scoped CSS, §8-justified) value?: number, lg?: boolean
EnergyPicker Interactive 5-step energy picker (clicking the current value resets to 0) modelValue?: number
DraggableBlock §7.1 canonical 2-line draggable block (PointerEvent drag; parent owns all positioning) line1Left, line1Right?, line2Left?, line2Right?, selected?, dragging?, density? (emits click, dragstart, dragend)

statusSeverity — single source of truth. apps/app/src/components-v2/shared/statusSeverity.ts is the canonical map from the five backend-mirrored status enums (ShiftAssignmentStatus, ArtistEngagementStatus, PaymentStatus, PersonStatus, MatchStatus) to PrimeVue Tag severity literals. StatusTag resolves through it and never inlines a severity. The map is bidirectionally test-locked by apps/app/tests/unit/utils/statusSeverity.consistency.spec.ts (every enum value maps to a severity; every map key is reachable from an enum). Changes to the map are RFC-level (design spec §8) — not an ad-hoc per-component decision.

AppTopbar <Menubar> chrome-wrap (Plan 3 Task 11, RFC AD-3). Convention: wrap, don't rewrite. The hand-rolled top-bar chrome is wrapped in <Menubar :model="[]"> with the breadcrumb in #start and the search / notifications / user cluster in #end. Menubar carries no menu items — it is the AD-3-mandated chrome shell only; its pt slots inherit the original layout classes verbatim so the wrap is visually identical to the pre-wrap (Plan-2) bar (human pixel-parity check at the HITL gate). Caveat: :model="[]" renders an empty <ul role="menubar"> — tracked as A11Y-AD3-MENUBAR-EMPTY-MODEL in BACKLOG.md § Technische schuld; resolve at the F5 a11y batch before reusing this pattern broadly.

DraggableBlock drag-model contract. The canonical PointerEvent drag model — reconciled from the two crewli-starter consumers (TimetableGrid

  • CueTimelineEditor) — is fixed by the A2 contract doc dev-docs/superpowers/plans/2026-05-17-gui-redesign-tier1-primitives-DRAGGABLEBLOCK-CONTRACT.md (commit dd45e899). Component is presentational; the parent owns all snap/lane/px math. Known gap: no @pointercancel handler — a system-cancelled drag emits a spurious dragend. Tracked as FRONTEND-DRAGGABLEBLOCK-POINTERCANCEL (blocked on an A2-contract amendment first).

1. Purpose and scope

This document defines:

  1. Which PrimeVue component (or Tailwind / native equivalent) replaces each Vuetify component used in the SPA today
  2. The Aura theme tokens that carry Crewli's brand (teal primary, dark mode)
  3. The canonical form pattern (@primevue/forms + Zod resolver + <FormField> wrapper)
  4. The canonical DataTable pattern (lazy / virtual / column-template conventions)
  5. When to use the pt (pass-through) API, Tailwind utilities, or Aura tokens for customization
  6. How to navigate the migration phase where Vuetify and PrimeVue both ship in the SPA simultaneously (F4aF4d)

Out of scope here:


2. When to read this document

Goal Read
Picking a PrimeVue equivalent for a Vuetify usage during F4 §3
Customizing Crewli's brand colors / dark mode §4
Writing or migrating a form §5
Migrating a <VDataTable> or <VDataTableServer> §6
Deciding between pt, Tailwind utility, or Aura token override §7, §8
Working on a not-yet-migrated surface during F4 §9
Understanding the test-runtime story during migration ARCH-TESTING.md §7

Cross-document relations:

  • RFC-WS-FRONTEND-PRIMEVUE.md — full migration plan, sprint breakdown, architectural decisions (AD-1 through AD-12), risk register
  • MIGRATION-AUDIT-PRIMEVUE.md — Vuetify usage inventory (§1), @core / @layouts surface area (§2), form-layer inventory (§4), DataTable inventory (§6)
  • VUEXY_COMPONENTS.md — deprecation stub; its pre-F2 content is reachable via git history (commit 1c449ff6204cae6371da08c34ea8934d6b2ffcb8) for reference on un-migrated surfaces
  • ARCH-TESTING.md §7 — explains why Vuetify lives in test infrastructure during the migration

3. Component mapping by category

The Crewli SPA uses ~73 distinct Vuetify components today (52 with ≥3 uses, 20 long-tail with <3 uses). The tables below group them into six functional categories. Each category is followed by one paragraph on the migration spirit — direct prop translation is rarely possible, since PrimeVue's customization model is pt + Tailwind, not Vuetify's deep-customization slots.

For component-level prop and slot reference, follow the linked PrimeVue docs URL — this document does not duplicate them.

3.1 Form inputs

Vuetify PrimeVue Reference Notes
VTextField InputText https://primevue.org/inputtext/ density='compact'size='small'; wrapped via <FormField> for label + error
VTextarea Textarea https://primevue.org/textarea/ Auto-resize via autoResize prop
VSelect Select https://primevue.org/select/ Renamed from Dropdown in v4; :items:options, item-titleoptionLabel, item-valueoptionValue
VAutocomplete AutoComplete https://primevue.org/autocomplete/ Server-side: bind @complete instead of :items
VCombobox AutoComplete with :multiple https://primevue.org/autocomplete/ Free-text + dropdown; PrimeVue uses one component for both
VCheckbox Checkbox https://primevue.org/checkbox/ binary prop for single-value checkboxes
VRadio / VRadioGroup RadioButton https://primevue.org/radiobutton/ No group component; bind v-model directly to each RadioButton
VSwitch ToggleSwitch https://primevue.org/toggleswitch/ Renamed from InputSwitch in v4
VOtpInput InputOtp https://primevue.org/inputotp/
VFileInput (rare) FileUpload https://primevue.org/fileupload/ mode='basic' for inline; default for full uploader
VColorPicker (2 uses) ColorPicker https://primevue.org/colorpicker/
AppDateTimePicker (Flatpickr) unchanged Flatpickr is retained per RFC AD-4; a thin DateTimePicker.vue wrapper composes Flatpickr inside <FormField>

Migration spirit. Form inputs are the highest-coverage area; nearly every input flows through <FormField> (§5). Most prop renames are trivial (densitysize, :items:options). The bigger shift is the validation contract: Vuetify's :rules array per field is replaced by a single Zod schema at the form level, with field-level errors surfaced through <FormField>. See §5 for the canonical pattern.

3.2 Layout

Vuetify Replacement Notes
VContainer <div class="max-w-screen-xl mx-auto px-4"> Tailwind utility composition; no PrimeVue equivalent
VRow <div class="grid grid-cols-12 gap-4"> Tailwind grid
VCol cols=N md=M <div class="col-span-N md:col-span-M"> Tailwind responsive prefixes
VCard Card https://primevue.org/card/ — slots: #title, #subtitle, #content, #footer
VCardTitle Card #title slot Compose inside Card
VCardSubtitle Card #subtitle slot
VCardText Card #content slot or <div class="p-6"> Most uses are pure padding
VCardActions Card #footer slot
VCardItem manual flex layout inside Card #content No direct equivalent
VDivider Divider https://primevue.org/divider/:verticallayout='vertical'
VSheet <div> with Tailwind No equivalent component
VSpacer <div class="flex-1"> or surrounding justify-between
VApp, VMain, VAppBar, VFooter layout shell rewrites See RFC AD-3; filenames preserved, contents replaced
VLocaleProvider PrimeVue <ConfigProvider> (or app-level app.use(PrimeVue, { locale })) See RFC AD-6

Migration spirit. Most layout in PrimeVue is Tailwind, not components. VRow/VCol translates 1:1 to a 12-column Tailwind grid. VCard is the biggest semantic preservation — its slot model maps to PrimeVue's Card slot model with minor renames. Plain <div> with Tailwind utilities replaces VSheet, VSpacer, and most uses of VContainer.

3.3 Data display

Vuetify PrimeVue / Replacement Reference Notes
VDataTable DataTable + Column https://primevue.org/datatable/ See §6
VDataTableServer DataTable with :lazy="true" https://primevue.org/datatable/#lazy_load See §6
VTable DataTable (no lazy) For static / pre-loaded tables
VList Listbox (selectable) or DataView (cards) https://primevue.org/listbox/ Context-dependent; selection lists use Listbox, card grids use DataView
VListItem / VListItemTitle / VListItemSubtitle MenuItem (in menu) or <li> (in list) Inside a list, just compose the row markup directly
VListSubheader <li class="text-sm text-surface-500"> Plain markup
VChip Tag (preferred) or Chip https://primevue.org/tag/ Tag for status badges; Chip for removable filters
VAvatar Avatar https://primevue.org/avatar/ variant='tonal':style="{ background, color }" (no built-in tonal)
VImg <img> (native) No wrapper needed; use loading="lazy"
VIcon <Icon name="tabler-..." /> Iconify-Tabler retained per RFC AD-5; thin wrapper at apps/app/src/components/Icon.vue over @iconify/vue's <Icon>. PrimeIcons is not installed
VLabel <label> (native) or <FormField label="...">
VTimeline / VTimelineItem Timeline https://primevue.org/timeline/
VBadge (1 use) Badge or OverlayBadge https://primevue.org/badge/

Migration spirit. VIcon is the most widespread component (267 uses) and it does not become a PrimeVue component. The Iconify-Tabler naming convention survives intact: call-sites use the existing tabler-* string identifiers (e.g. tabler-arrow-right) and the new apps/app/src/components/Icon.vue wrapper renders them through @iconify/vue as real <svg> markup. UnoCSS-style i-tabler-* utility classes were considered but not adopted (UnoCSS is not in the stack); the wrapper preserves Crewli continuity. PrimeIcons is not installed; do not introduce pi pi-* icon classes during F4 — they will not render. Lists are the most context-dependent area: a selection list uses Listbox, a card grid uses DataView, a navigation list uses MenuItem/PanelMenu, and a generic display list is just <ul><li>.

3.4 Feedback

Vuetify PrimeVue Reference Notes
VAlert Message https://primevue.org/message/ typeseverity; inline alerts only
VSnackbar useToast() + <Toast> https://primevue.org/toast/ One <Toast> mounted in App.vue; useNotificationStore wraps useToast() so call-site API stays stable per RFC AD-11
VProgressLinear ProgressBar https://primevue.org/progressbar/ :indeterminatemode='indeterminate'
VProgressCircular ProgressSpinner https://primevue.org/progressspinner/
VSkeletonLoader Skeleton https://primevue.org/skeleton/ type='card' has no preset; compose with explicit width, height, shape

Migration spirit. Message is for inline alerts (rendered in the page). Toasts are global, mounted once in App.vue, and triggered via useToast() (or the existing useNotificationStore which now wraps it). Skeleton is more primitive than VSkeletonLoader — Vuexy's preset shapes (type='card', type='article') need to be reconstructed from explicit Skeleton elements; do this once as a project-owned <SkeletonCard> utility if a shape is reused.

3.5 Navigation

Vuetify PrimeVue Reference Notes
VTabs / VTab / VWindow / VWindowItem Tabs + TabList + Tab + TabPanels + TabPanel https://primevue.org/tabs/ Single component family; controlled via :value
VBtnToggle SelectButton https://primevue.org/selectbutton/
VPagination (1 use) Paginator https://primevue.org/paginator/ DataTable has built-in paginator; standalone use is rare
VBreadcrumbs (none today) Breadcrumb https://primevue.org/breadcrumb/ Reserved for future use
VNavigationDrawer layout-shell custom + PanelMenu (or Drawer for mobile) https://primevue.org/panelmenu/, https://primevue.org/drawer/ Sidebar nav is part of the shell rewrite per RFC AD-3; PanelMenu provides accordion behavior equivalent to VVerticalNavGroup
Vuexy AppStepper Stepper + StepList + Step + StepPanels + StepPanel https://primevue.org/stepper/ Multi-step wizards (e.g., public registration)
Vuexy VerticalNavLayout layout shell rewrite See RFC AD-3

Migration spirit. PrimeVue's Tabs family expands one Vuetify component into five elements (Tabs / TabList / Tab / TabPanels / TabPanel). This is more verbose at call sites but more flexible (e.g., tab list can live separately from panels). The sidebar / nav shell is a rewrite, not a component swap — Vuexy's @layouts/ system is replaced wholesale per RFC AD-3, but route-level nav semantics (Pinia stores, route meta) stay the same.

3.6 Overlays

Vuetify PrimeVue Reference Notes
VDialog Dialog https://primevue.org/dialog/ :max-width='500':style="{ width: '500px' }"; :fullscreen:maximizable
VMenu Menu (action lists) or Popover (rich content) https://primevue.org/menu/, https://primevue.org/popover/ Choose Menu for MenuItem lists, Popover for arbitrary slot content
VTooltip v-tooltip directive https://primevue.org/tooltip/ Directive form (v-tooltip="'Hint'") is preferred over a wrapping component
VOverlay Dialog with modal prop, or custom <div> Most overlay uses are modal dialogs
VBottomSheet (none today) Drawer with position='bottom' https://primevue.org/drawer/ Reserved; mobile bottom-sheets if needed
VExpansionPanel(s) Accordion + AccordionPanel + AccordionHeader + AccordionContent https://primevue.org/accordion/ Renamed in v4 from AccordionTab
VExpandTransition / VScaleTransition Vue <Transition> (native) Native transitions; Vuetify-specific transitions removed
Native confirm() / Vuexy ConfirmDialog useConfirm() + <ConfirmDialog> https://primevue.org/confirmdialog/ Mounted once in App.vue per RFC AD-11

Migration spirit. Overlays are services in PrimeVue: useToast(), useConfirm(), useDialog(). The pattern is one mount in App.vue, many calls from anywhere. Dialog itself is still a component (not a service) for non-confirm modals — keep <Dialog v-model:visible="..."> for create/edit forms.


4. Aura theme and Crewli tokens

PrimeVue 4 uses CSS custom properties under the --p-* prefix, generated from a JS preset. Crewli's preset extends Aura and overrides only the primary color (teal) and dark-mode contrast colors. Full token plan is in RFC Appendix B; F3 implements apps/app/src/plugins/primevue/theme.ts.

Key conventions:

  • Primary color is Crewli teal (#0D9394), defined as primary.500 in the preset
  • Dark mode uses darkModeSelector: '.dark' (matches Vuexy's existing dark-class strategy on <html>); the same toggle that flips Vuetify's dark theme today flips PrimeVue's, so no UI change for users
  • Surface, formField, list, navigation, overlay, content tokens use Aura defaults (no override needed)
  • Brand-color customization at the component level happens via the pt API (§7), not via CSS overrides

Do not introduce --p-* overrides directly in SCSS during F4. If a brand adjustment is needed, extend the preset in theme.ts so the override is centralized and dark-mode-aware.


5. Forms pattern (canonical)

The form layer is @primevue/forms plus a Zod resolver, called through a Crewli-owned <FormField> wrapper at apps/app/src/components/forms/FormField.vue.

The full API specification — usage example, prop contract, slot contract, useFormError 422 integration, error precedence — lives in RFC-WS-FRONTEND-PRIMEVUE Appendix A. That is the single source of truth; it is intentionally not duplicated here so that revisions to the API only need to land in one place.

What this document encodes (Crewli conventions on top of the API):

  1. One Zod schema per form, defined at the top of the component or hoisted to apps/app/src/schemas/[module].ts if reused. Schema field names mirror the backend Form Request field names exactly (snake_case) so 422 errors map back without translation.
  2. <FormField name="..." label="..." required> wraps every PrimeVue input. The wrapper's name prop matches the Zod schema key and the input's :name prop. Labels are Dutch by Crewli convention.
  3. Server validation (422): catch in the onSubmit handler, call applyApiErrors(e.response.data.errors) from useFormError(formRef). Field-level messages are injected via <FormField :apiError="...">; manual errors refs are not used.
  4. No mixed validation. A single form is either fully Zod-validated (target) or fully :rules-validated (legacy Vuetify). Do not introduce a hybrid.
  5. Migration phase: existing forms keep their current ref({}) + VForm + :rules + errors pattern until the surrounding surface is migrated. Per F4 sub-package, all forms on that surface flip to PrimeVue + <FormField> + Zod resolver in one commit. See §9.

VeeValidate is not the form library. It was previously listed in CLAUDE.md but never adopted; the form layer is @primevue/forms + Zod resolver per RFC AD-1.


6. DataTable pattern

<DataTable> replaces both VDataTable (client-side) and VDataTableServer (server-side). The full DataTable inventory is in MIGRATION-AUDIT-PRIMEVUE §6; the strategy is in RFC AD-7.

Conventions:

Need PrimeVue API Notes
Server-side pagination/sort/filter :lazy="true", :totalRecords, @page / @sort / @filter event handlers Replaces VDataTableServer's :items-length + @update:options
Custom cell rendering <Column field="..."><template #body="slotProps">...</template></Column> Replaces Vuetify's #item.fieldName slot
Custom header rendering <Column><template #header>...</template></Column> Replaces #header.fieldName
Expandable rows expandedRows v-model + <template #expansion> https://primevue.org/datatable/#row_expand
Row selection selection v-model + selectionMode="single" / "multiple"
Virtual scrolling (>1000 rows) :virtualScrollerOptions="{ itemSize: 50 }" Replaces v-data-table-virtual
Empty / loading / error states <template #empty>, :loading, surrounding error wrapper The three-state pattern (loading / error / empty) per CLAUDE.md UI rules is preserved

Slot translation cheat sheet:

VDataTable slot DataTable equivalent
#item.email <Column field="email"><template #body="{ data }">{{ data.email }}</template></Column>
#header.actions <Column><template #header>Acties</template></Column>
#expanded-row <template #expansion="{ data }">...</template>
#no-data <template #empty>...</template>
#loading :loading prop + loadingIcon
#top sibling <div> above <DataTable>; not a built-in slot

Per-page conventions:

  • One <DataTable> instance per page; no nested data tables
  • Server-side tables wire to a TanStack Query composable that returns { data, isLoading, isError, refetch }; the composable's params (page, perPage, sortBy, filters) are driven by reactive refs that PrimeVue's @page / @sort / @filter handlers update
  • Column widths are not set in props for the common case; use pt on <Column> only when a fixed width is structurally needed
  • Selection state is a Pinia store only if it crosses components (e.g., bulk-action toolbar); inline selection stays local

7. Pass-through (pt) API and slot conventions

PrimeVue's primary customization mechanism is pt (pass-through), which targets named DOM nodes inside a component and applies attributes/classes to them.

<Button label="Opslaan" :pt="{
  root: { class: 'shadow-md' },
  label: { class: 'font-semibold' }
}" />

Decision matrix — when to reach for which tool:

Need Use
Layout, spacing, typography around a component Tailwind utility classes on the wrapping <div>
Internal styling of a component's DOM (e.g., the Button's root <button>) pt
Brand color, dark-mode-aware token Aura preset extension in theme.ts (§4)
One-off override that doesn't fit the above <style scoped> as last resort, with a comment explaining why

Slot conventions vs. Vuetify:

  • Most named slots map 1:1 in name (#default, #footer), but slot prop shapes differ — always check the PrimeVue docs page for the exact slot signature
  • PrimeVue's slot system is generally narrower than Vuetify's; deep customization that Vuetify did via slots is done in PrimeVue via pt
  • Default slots receive no implicit data in most components — read the doc page if a slot returns nothing useful

8. Tailwind v4 + PrimeVue integration

Tailwind v4 with the tailwindcss-primeui plugin is installed alongside PrimeVue per RFC AD-12. Configuration lives in F3.

Source-order conventions (CSS cascade matters):

  1. PrimeVue base styles (auto-injected by the plugin)
  2. Aura theme tokens (from theme.ts)
  3. tailwindcss-primeui exposes Aura tokens as Tailwind utilities (bg-primary, text-surface-500, etc.)
  4. Tailwind utility classes in templates
  5. Project-scoped CSS (last resort)

When to reach for what:

Need Tool
Margin, padding, flex, grid, gap Tailwind utility class
Text color, background, border using brand tokens Tailwind utility from tailwindcss-primeui (bg-primary-500, text-surface-700)
Component-internal restyle pt on the component
Brand-wide override Aura preset extension

Avoid mixing arbitrary HEX values into templates. If a color is reused twice, it belongs in the Aura preset; reference it via the surface / primary scale token instead of literal HEX.


9. Migration phase guidance

During F4 (sub-packages F4aF4d), the SPA contains both Vuetify and PrimeVue components in the same build. The discipline that keeps this sane:

  1. Surface-level consistency. Within one route or component tree, use one framework. Never mix <VTextField> and <InputText> in the same form, never mix <VBtn> and <Button> in the same toolbar. The unit of migration is a surface (a route or a feature folder), committed as a sub-package.
  2. No back-porting. Do not migrate "just one component" inside a not-yet-migrated surface. The sub-package is the smallest migration unit.
  3. Pre-migration: follow Vuetify. If you are extending an un-migrated surface during F4 (e.g., bug fix on /portal/* while F4b is in progress on the organizer root), follow the conventions visible in the surrounding code. The pre-F2 VUEXY_COMPONENTS.md content is reachable at git commit 1c449ff6204cae6371da08c34ea8934d6b2ffcb8 for reference.
  4. Post-migration: follow PrimeVue. Any new code on a migrated surface follows this document. New surfaces (created during or after F4) start in PrimeVue.
  5. Tests during migration. Vuetify stays in test infrastructure for surfaces that haven't migrated yet. See ARCH-TESTING.md §7 for the test-runtime story; setupFile flips per RFC AD-10.
  6. When in doubt, prefer PrimeVue conventions. If a form on a migrated surface needs a component this document doesn't yet cover, find the closest PrimeVue equivalent on https://primevue.org/, implement it, and append a note in §3 (or open a tightly scoped PR to update this document). F4 sub-packages are expected to refine §3 — that is the explicit growth path.
  7. F6 is the cliff. After F6 (cleanup, ~0.5 day), Vuetify is removed from package.json and <V*> tags fail to compile. No more parallel mode. Per RFC §9, F6 is the point of no return for rollback.

Anti-pattern: directly applying responsive visibility utility classes (md:hidden, lg:flex, etc.) to PrimeVue components. PrimeVue's component CSS may override due to cascade order. Always wrap in a plain element that owns the visibility class.


10. Cross-references and resources

External (PrimeVue ecosystem):

Internal (Crewli docs):

  • RFC-WS-FRONTEND-PRIMEVUE.md — full migration plan, AD-1 to AD-12, sprint breakdown, risk register, FormField API (Appendix A), Aura theme tokens (Appendix B), version pinning policy (Appendix C)
  • MIGRATION-AUDIT-PRIMEVUE.md — F1 audit: Vuetify usage inventory (§1), @core / @layouts surface area (§2), Vuetify config and theme (§3), form-layer inventory (§4), page and route inventory (§5), DataTable inventory (§6)
  • ARCH-TESTING.md — test-tier decision tree; §7 covers the Vuetify-in-test-infra temporary state during the migration
  • VUEXY_COMPONENTS.md — deprecation stub; pre-F2 content recoverable via git commit 1c449ff6204cae6371da08c34ea8934d6b2ffcb8
  • CLAUDE.md — project-wide conventions; UI section now points here

This document is a foundation. F4 sub-packages will extend §3 with component-level migration notes as real surfaces are converted; expect diff PRs against this file alongside each sub-package commit.