Link
A single-record picker for a Frappe doctype. Composes Combobox and fetches its options directly from frappe.desk.search.search_link — pick a doctype, and the rest works.
Simple
A bare picker. v-model carries the selected record's primary key (a string), or null when nothing is selected.
Labeling, Description, Error, Required
Link accepts the standard input labeling props — label, description, error, required — and forwards them to the underlying Combobox, so ARIA wiring (aria-required, aria-invalid, aria-errormessage) and the InputLabel chrome render identically to a standalone Combobox.
Filters
The filters prop is a Record<string, unknown> passed straight through to search_link. Frappe's underlying endpoint also accepts list-form and SQL-string filters, but the component boundary intentionally narrows to the dict form — it covers every CRM call site without leaking backend serialization into the public API. Reactive — changing filters triggers a refetch. The #footer slot is the canonical home for a filter-status row (or any non-selectable popover affordance) and renders below both the options list and the creatable create-new row.
Creatable
creatable: true injects a "Create" row at the bottom of the popover, visible only when the user has typed. Clicking it emits @create with the typed query — the consumer owns the create flow (typically a dialog) and assigns the freshly-created record back to v-model on success. To replace the default create row markup (icon, helper text, copy), supply the #item-create slot — scope is { query }.
Suffix
By default, Link renders a clear button in the suffix slot when modelValue is non-null and required: false. To replace it with your own affordance — an "Open record" link, an "Edit" button — supply #suffix. The slot fully takes over; if you still want a clear button alongside your action, render one yourself. To dismiss the options dropdown when your action takes over (e.g. opens a dialog), bind v-model:open and set it to false.
Member Picker
Link forwards every Combobox per-row slot — #item-prefix, #item-label, #item-suffix, #item — so a doctype picker can render an avatar, role, or any other contextual chrome without dropping down to <Combobox> directly.
Combobox passthrough
Link composes Combobox and forwards unrecognized props via $attrs and all non-overridden slots. Anything in the Combobox API that Link doesn't claim itself (options, loading, and the #suffix / #item-create slots which have Link-specific defaults) reaches the underlying component unchanged.
API Reference
Show types
import type { InputLabelingProps } from '../../src/composables/useInputLabeling'
export interface LinkProps extends InputLabelingProps {
doctype: string
filters?: Record<string, unknown>
creatable?: boolean
disabled?: boolean
placeholder?: string
}
export interface LinkEmits {
'update:modelValue': [value: string | null]
'update:open': [value: boolean]
create: [query: string]
}
export interface LinkExposed {
reload: () => void
}
export type LinkOption = {
label: string
value: string
description?: string
}Label rendered above (or beside, for binary controls) the input.
Helper text rendered below the input. Hidden when `error` is set.
Error message rendered below the input. When set, the control receives `aria-invalid="true"` and `data-state="invalid"`. May be either a string or an `Error` object whose `messages?: string[]` is rendered as stacked lines (with `Error.message` as the fallback).
Marks the field as required. Renders an asterisk next to the label and forwards `required` / `aria-required` to the underlying control.
HTML id of the underlying control. Auto-generated via `useId()` if omitted.
| Slot | Payload |
|---|---|
suffix | { open: boolean; disabled: boolean; query: string; selectedOption: ComboboxSelectableOption | null; |
| Event | Payload |
|---|---|
update:modelValue | unknown[] Fired when the model value changes. |
update:open | unknown[] Fired when the open state changes. |
create | [query: string] |
Fired when the model value changes.
Fired when the open state changes.