This is the main planning document for the frappe-ui v1 release.
Keep separate docs only where that genuinely helps:
04-components-audit.mdfor the component audit matrix08-selection-and-menu-api-spec.mdfor the accepted menu/selection API direction08f-dialog-spec.mdfor the accepted Dialog + imperativedialog.*API direction09-input-components-spec.mdfor the accepted input-family API direction (TextInput, Textarea, Password, Checkbox, Switch, Rating, Slider, ErrorMessage; FileUploader covered separately)
frappe-ui v1 is a narrow, API-freeze-first release.
The goal is not to make every part of the repository feature-complete. The goal is to make the core component surface and the recommended data API path stable enough to support a long-lived 1.x line without immediate breaking corrections.
In practice, v1 means:
- core component APIs are stable and audited
- core components are modernized to TypeScript,
<script setup>, docs, stories, and tests - v3 data APIs are the recommended path for new work
- Gameplan is fully migrated to v3 before the tag
- v1 resource APIs and v2 composables remain exported for migration, but are deprecated
- legacy APIs/components move out of the happy path and into migration/legacy docs
TextEditorships with a narrower default surface for v1- the release is backed by docs refresh, migration guidance, deprecation warnings, and an RC validation pass
- Stabilize what people should use next.
- for components, that means the core public component set
- for data APIs, that means v3
- Keep migration paths open.
- deprecated APIs stay available during the transition
- Use a real app to validate the new direction.
- Gameplan is the proving ground for v3
- Avoid unnecessary breadth before freeze.
- non-core areas should not silently become blockers
All core components must be:
- implemented in TypeScript
- implemented with
<script setup> - documented
- covered by baseline stories
- covered by baseline component tests
- audited for API consistency and stability
Core set:
- Alert
- Avatar
- Badge
- Breadcrumbs
- Button
- Checkbox
- Combobox
- DatePicker
- MonthPicker
- TimePicker
- Dialog
- Divider
- Dropdown
- ErrorMessage
- FileUploader
- FormControl
- ListView
- MultiSelect
- Password
- Popover
- Progress
- Rating
- Select
- Sidebar
- Slider
- Switch
- TabButtons
- Tabs
- TextEditor
- TextInput
- Textarea
- Toast
- Tooltip
- Tree
- Calendar
- Resource
- VueGridLayout
These can still exist in the package, but they are not part of the v1 stabilization contract.
We have only agreed on a small set of broad component decisions so far.
- keep component boundaries narrow across the library
- keep app-facing public APIs high-level where possible
- prefer props and slots for ordinary usage
- avoid giant do-everything components
- avoid exposing low-level composition as the default public API story
- use
v-model/modelValuefor the primary value state - use
v-model:openfor visibility state - expose named secondary models only when clearly needed
- keep query internal by default unless a stronger need emerges
- use stable styling hooks like
data-*and ARIA state to simplify styling and testing - prefer slots over
renderas the default customization pattern - keep escape hatches limited and requirement-driven
- keep polymorphism limited to real needs, such as
Buttonrendering as an anchor or router link
For the selection/menu family, ItemListRow is the shared row primitive used internally by Dropdown, Select, Combobox, and MultiSelect. Each higher-level component owns its own listbox shell (keyboard nav, grouping, empty/footer slots, etc.); only the row presentation is shared.
Use 08-selection-and-menu-api-spec.md as the source of truth for that family.
We have not yet agreed on broad reusable rules for every complex component family. Dialog, Tooltip, Tabs, and other overlay/component families still need separate design passes.
Examples:
createResourcecreateListResourcecreateDocumentResourceresourcesPluginResource.vue
Status for v1:
- still exported
- supported as migration path
- deprecated for new usage
- hidden from standard docs
- documented only on the legacy page and migration guide
- should warn in dev mode
Examples:
useListuseDocuseCalluseDoctypeuseNewDoc
Status for v1:
- still exported
- not deprecated for 1.0 — supported
- recommended for Frappe v15 and for codebases not yet on v3
- no dev-mode deprecation warnings
- documented in main docs
Rationale: v3 ships in 1.0 but is recommended only for Frappe v16+. v2 remains the supported path for v15 users and existing codebases. v2's eventual fate is a post-v1 decision tied to v3 adoption and v15 backport status.
Implemented in PR #610 (frappe/client/). Exports from
frappe-ui/frappe/vue:
createClientcreateDefaultCacheAdapterdefineDoctype(returned fromcreateClient)- doctype handles: doc / list / count / newDoc
Status for v1:
- ships in 1.0 (merged from PR #610)
- recommended path for new code on Frappe v16+
- frozen public import surface —
createClientand the public types/exports above are stable for the 1.x line - internal signatures may evolve in 1.x minors via deprecation cycles only — no breaking changes
- partial Gameplan migration provides the stress-test signal; full migration is post-v1
What is frozen for 1.0:
- import path
frappe-ui/frappe/vue createClientexists and returns{ defineDoctype, store }plus the client objectcreateDefaultCacheAdapter(name: string)exists- doctype handles for doc / list / count / newDoc exist and are reactive
- public type exports (props, return types of
createClient, handle types)
What may evolve (only via deprecation cycle in 1.x):
- specific method names on handles
- option keys on
createClient - ergonomic additions (new methods, new options)
- cache adapter contract internals
- PR #610 self-reviewed against
frappe/client/spec/*.md - smoke-tested against the partial Gameplan v3 migration
- merged with a one-time dev-mode notice on
createClient(e.g. "v3 is recommended for Frappe v16+") - frozen surface contract documented (see section above)
- migration path from v1 resources documented on the legacy page (v2 → v3 deferred to post-v1)
v3 depends on /api/v2/* endpoints in Frappe Framework.
Decision:
- Frappe v15 backport work does not block v1
- v3 can be recommended for Frappe v16+
- the v15 backport belongs in the post-v1 roadmap unless it lands naturally earlier
Use medium-aggressive warnings in development:
- warn once per deprecated API/component per session or module lifecycle
- include the replacement and a migration-doc reference when possible
Keep exported for migration:
- v1 resource APIs
- v2 composables
Resource.vueInput.vueAutocompleteFeatherIcon
Resource.vue: deprecated and hidden from standard docsInput.vue: deprecated in favor of the modern input/control stackAutocomplete: deprecated in favor of the split selection/menu componentsFeatherIcon: export retained for back-compat. Components that accept icon-name props (e.g.Button.icon,Dialog.icon,Dropdownitem icons) continue to render feather names throughFeatherIconso existing call sites do not break. Internal hardcoded icon usages migrate tolucide-*strings via the shared Tailwind plugin. Docs recommendlucide-*(or a passedComponent) for new code.
Bring the full core component set to the baseline standard:
- TypeScript
<script setup>- docs
- stories
- tests
- API audit
Also remove internal FeatherIcon use across core components.
See 08-selection-and-menu-api-spec.md.
Key items:
- deprecate
Autocompletein favor of separate higher-level components - finalize
ItemListRowas the shared row primitive - finalize
Select,Combobox,Dropdown,MultiSelect,FormControl, andSwitch - align the family on
v-model,v-model:open, shared trigger/item slot vocabulary, and@update:query - deprecate
Input.vue
- Dialog cleanup/finalization
- floating utilities consolidation
- improve consistency across Dialog, Popover, Dropdown, Select, Combobox, and Tooltip
- align vocabulary like
open,side,align,placement, andoffsetwhere practical
v1 carve-out: TextEditor's public API is not frozen for 1.0. The component ships in 1.0 as-is. A full refactor (internals + public API redesign + the open behavioral fixes) lands in 1.1 with a documented migration path. Until then, the existing TextEditor surface is supported unchanged.
Required for 1.0:
- no changes to
TextEditor.vuepublic API - release notes explicitly state the carve-out
Deferred to 1.1 (bundled into a single refactor effort):
- default-off font family / font size policy
- backtick block highlighting fix
- line-height cleanup
- internal modernization (TS +
<script setup>for sub-components) - public API redesign with deprecation cycle / migration path
- table editing UX improvements
- collapsible section / additional editor features
v1 scope: v3 ships in 1.0 via PR #610 with a frozen public import surface (see "Data API strategy" above). Full Gameplan migration is post-v1.
Required for 1.0:
- PR #610 self-reviewed and merged
- partial Gameplan migration used as the stress-test signal
- frozen surface contract documented
- one-time dev-mode notice on
createClient("v3 is recommended for Frappe v16+")
Post-v1 umbrella: full Gameplan migration off v1 resources, eventual v2 deprecation decision, Frappe v15 backport, DocType Meta composable, related ergonomics. Tracked as a single post-v1 umbrella issue.
Required outputs:
- docs refresh for core components
- v3 data docs
- migration guide
- single legacy APIs/components page
- deprecation warnings in dev mode
- release candidate validation
Legacy page should include at minimum:
createResourcecreateDocumentResourcecreateListResourceResource.vueresourcesPluginInput.vueAutocompleteFeatherIcon
v2 composables (useCall, useDoc, useList, useDoctype, useNewDoc)
stay in the main docs — they are not deprecated for 1.0.
v1 should not ship before all of these are done:
- release contract and quality gates are defined
- core components are migrated to TypeScript and
<script setup>and have docs/stories/tests baselines (FileUploader, TabButtons, ListView remaining) - selection/input family stabilization is complete enough for v1
- Dialog/floating stabilization is complete enough for v1
- TextEditor 1.0 carve-out documented (public API unchanged; refactor in 1.1)
- v3 PR #610 merged with frozen surface contract documented
- file uploads default to
is_private: true(security #206) - color tokens aligned with Figma
- deprecation warnings and legacy docs exist
- internal hardcoded
FeatherIconusage is migrated tolucide-*(prop-driven icon-name paths kept for back-compat) - migration guide and release candidate validation are complete
More specifically, the selection/input family blocker set includes:
Autocompletedeprecated in favor of separate higher-level componentsItemListRowfinalized as the shared styled row primitive used byDropdown,Select,Combobox, andMultiSelectSelect,Combobox,Dropdown, andMultiSelectfinalized on top of that foundationFormControlfinalizedSwitchfinalizedInput.vuedeprecated
These stay in the plan, but should not block 1.0.0:
- session and user utilities
- first-class socket.io utilities
- full migration of
frappe-ui/frappe/*internals to v3 - Frappe v15
/api/v2/*backport - TextEditor table editing UX improvements
- downstream migration PRs across all products
- Calendar stabilization
- VueGridLayout modernization
Do not tag 1.0.0 until all of the following are true:
- lint passes
- typecheck passes
- unit tests pass
- component tests pass
- core component docs are complete
- legacy docs page exists
- migration guide exists
- deprecation warnings exist for v1/v2/legacy components
- Gameplan is fully on v3 data APIs
- release candidate has been validated
These are important, but should not block v1 unless they land naturally earlier.
- Frappe v15
/api/v2/*backport - session and user utilities
- first-class socket.io utilities
- broader internal migration of
frappe-ui/frappe/*to v3
- TextEditor table editing UX improvements
- Calendar stabilization and future promotion into the core set if appropriate
- deeper component coverage beyond the baseline docs/stories/tests standard
- downstream app migration wave
- broader deprecation cleanup follow-through
- eventual removal strategy for legacy exports in a future major version
Within the first 1.x cycle, the project should be able to say:
- new apps use v3 by default
- core components no longer depend on deprecated internal primitives
- Gameplan is stable on v3
- deprecated usage across products is decreasing