Skip to main content

useRecordLink

Turns "open this record" into a click handler and, when the target opens on an overlay, the dialog that hosts it.

The generated views wire it up behind every record chip. Reach for it when you build a control that should open a record the way the rest of the admin does — honouring ctrl-click, in-place navigation inside a dialog, and docking into the side panel.

Signature​

import { useRecordLink } from "habarico";

const { handleClick, dialog } = useRecordLink({
viewType: "show",
linkMode: "dialog",
renderContent,
});

It reads the record and the resource from context, so it opens whatever record it is mounted under.

Parameters​

NameTypeDefaultDescription
viewType'show' | 'edit'—Which view to open; without it the link is not offered at all
keepLinkedParentbooleanfalseKeeps the linked parent segments in the redirect path
linkMode'page' | 'dialog' | 'panel''page'Surface the target opens on
dialogWidthstring"md"MUI breakpoint or CSS width, for linkMode: 'dialog'
changeView(props) => boolean—Swaps the content of the dialog the link was clicked in, in place; return false to fall back to a redirect
openSidePanel(props) => boolean—Docks the record into a side panel; return false to fall back to a dialog
renderContent(props) => ReactNode—Renders the body of the overlay

changeView and openSidePanel receive {resource, viewType, viewName, id}; renderContent also gets data and an onClose.

Returns​

NameTypeDescription
handleClick(e: MouseEvent) => void | undefinedBind to the element's onClick; undefined when there is no view to open
dialogReactNodeRender alongside the element — it is empty unless an overlay is open

handleClick is undefined whenever viewType, the record or the resource is missing. That is the signal to render the control as inert rather than as a dead link.

Behaviour​

  • linkMode: 'page' navigates, resolving the modifier keys into same tab / new tab / new window — so ctrl-click keeps working without extra code.
  • linkMode: 'panel' docks into the side panel, unless the click came from inside that same panel: docking it again would replace the panel with itself, so that case opens a dialog on top.
  • Clicked from inside a dialog, an overlay link asks changeView to swap the dialog's content in place instead of stacking a second dialog; a falsy return redirects instead.
caution

linkMode: 'dialog' or 'panel' without a renderContent throws. There is nothing sensible to put in the overlay, and failing at the call site beats opening an empty dialog at runtime.

useSchemaRecordLinkOptions​

The schema half of the same link. It resolves the schema-level link onto a concrete viewType — a resource may expose no show view, or no edit view, in which case no link is offered — and supplies the schema's own view router as renderContent, plus changeView and openSidePanel from the surrounding view.

import { useRecordLink, useSchemaRecordLinkOptions } from "habarico";

const { handleClick, dialog } = useRecordLink({
...useSchemaRecordLinkOptions({ link: "show" }),
linkMode: "dialog",
dialogWidth: "lg",
});
NameTypeDefaultDescription
linkboolean | 'show' | 'edit'—Whether to link, and to which view; true prefers show and falls back to edit

It returns only the four options a schema can supply — viewType, changeView, openSidePanel and renderContent. keepLinkedParent, linkMode and dialogWidth are the caller's own and go to useRecordLink directly, which is why they do not appear here.

tip

It stops at the options rather than calling useRecordLink for you, because RecordRepresentationChip calls the hook itself — spread these into its props and let it do the resolving.

See also​