An effort is underway to create a new unified interface for adding / editing links within the editor. It may look something like this:

Work is already underway to implement this.
What follows below is an analysis and recommendation for how we can go about introducing this new standardised link interface into Gutenberg.
This has been prompted by several discussions as to the best technical route to take in order to allow us to introduce this new UI across the editor with a minimum of disruption.
I will begin with an overview of the existing interface components that provide link-related UI.
I will then analyse how/whether it is possible to modify the existing components to realise the new link UI design.
Following on from this, I will then discuss how the current link interfaces within Gutenberg are created.
Finally, I will propose a route forward centred around creating a single unified component for link interfaces within Gutenberg.
Overview of existing "link" Components
The following components are already available within Gutenberg and are used for creating "link" interfaces.
URLInput

- desc: a text input that accepts a search query or a URL. Provides search suggestions for matching
Posts and Pages as you type. URLs are not handled as search suggestions.
- location:
packages/block-editor/src/components/url-input
- features/functionality:
- text input box for typing searches or for URL entry
- search suggestion list appears when typing
- search results "fetching"
- a11y affordances around
listbox ARIA attrs
- keyboard controls
- focus management
- usage notes: this component is almost always used as part of
URLPopover.LinkEditor and is only ever used in isolation within packages/block-library/src/button/edit.js. This component is low level. It does not provide a popover or a settings drawer. Therefore when used in isolation it will not provide the design for the new Link UI. Therefore it is ill suited as a wrapper component.
URLPopover


- desc: renders a popover for displaying a UI for adding/editing a link. Comes with a "drawer" for rendering contextual items relating to the URL (eg: additional settings such as "Open in New Tab"). Utilises
URLInput and ExternalLink internally.
- location:
packages/block-editor/src/components/url-popover
- features/functionality:
- popover UI which displays above other content and contains the rest of the link UI
- toggable link settings area - often used to display "new tab"...etc
- additional controls area - space to render any custom UI within the popover but undereath the primary UI elements
- usage notes: this component is most often utilised as a wrapper around
URLInput, with URLInput provinding the input and search suggestions and URLPopover providing the settings drawer, "selected" states and a popover in which to contain the UI.
URLPopover also exposes the following sub components:
URLPopover.LinkEditor
- location:
packages/block-editor/src/components/url-popover/link-editor.js
This provides a simple wrapper around URLInput to provide a <form> tag and a Apply button.
URLPopover.LinkViewer
- location:
packages/block-editor/src/components/url-popover/link-viewer.js
This provides a simple style for "selected" links. It is a wrapper around ExternalLink and also provides an "Edit" button.
How are link interfaces currently creating within Gutenberg?
As it stands the two existing components URLInput and URLPopover are largely low level components. Therefore, it is important to appreciate that in almost every case where a link interface is required within Gutenberg, these components are consumed and controlled by the parent component (via props) to create a bespoke interface.
This happens each time a link UI is created.
Some good examples of this are:
What we can observe here is that each time an interface for adding links is required, the developer is currently required to wire together a bespoke implementation.
In short, there is currently no unified interface component for creating link UIs in Gutenberg.
Conclusion and Recommendation
Based on the evidence above, it appears that what is required is not extensive modification or refactoring of the existing URL* components, but rather the creation of a single component which wires together the lower-level components to provide a unified link interface.
Given that URLInput is a low level component which is already in use, attempting to refactor this to be a wrapper around a more complex, fully unified Link UI would be complex, time-consuming and provide little or no benefit.
Similarly, URLPopover is largely a visual component and should not be a candidate for managing state or a fully unified UI.
Therefore, the most effective and expedient solution is to create a new component which unifies the existing components under a single interface.
By doing this we will provide the following benefits:
- developers will only need to consume a single component to create a link UI.
- standardising under a single link UI component will bring visual and UX consistency to link interfaces throughout Gutenberg.
- work on existing
URLInput and URLPopover components can be preserved and reused - no need for deprecations.
- small modifications to existing
URLInput and URLPopover will make these more flexible for future if/when required to create bespoke/highly customised link UIs that cannot be serviced by the unified component.
The new component can be relased as "experimental" and then once accepted, it can gradually used to replace the existing bespoke usages of URLPopover and URLInput thereby standardising link intefaces across Gutenberg.
This approach has already been trialled in this PR.
Appendix A: do we need to modify the existing components to deliver the new design?
The following changes are required to both components in order to realise the new design:
Changes to URLInput
-
Update rendering of suggestion items to add in more information about the suggestion (see Design) - this can be achieved by either:
- modifying the search suggestions render within the
URLInput directly (note: this means all existing implementations will inherit this change).
- adding a optional render prop to
URLInput to allow parent/consuming components to modify the rendered output of suggestion items (as per current LinkControl PR).
-
Update the placeholder on the input - this is most easily achieved by exposing a placeholder prop on URLInput.
-
Fix to ensure that suggestions are hidden when the input is empty.
-
Design requires that when a URL is entered this is displayed as a search suggestion. Currently URLInput will ignore URLs when calling the function prop which fetches search suggestion data. This can be fixed by:
Changes to URLPopover
Given that it is mainly a wrapper component, it is unlikely that it would be useful to make changes to URLPopover. Almost every example of a Link UI within Gutenberg consumes URLPopover as a controlled component. All state management and customisation is handled outside of URLPopover.
The only major changes required to realise the new design would be:
Appendix B: Related Links
An effort is underway to create a new unified interface for adding / editing links within the editor. It may look something like this:
Work is already underway to implement this.
What follows below is an analysis and recommendation for how we can go about introducing this new standardised link interface into Gutenberg.
This has been prompted by several discussions as to the best technical route to take in order to allow us to introduce this new UI across the editor with a minimum of disruption.
I will begin with an overview of the existing interface components that provide link-related UI.
I will then analyse how/whether it is possible to modify the existing components to realise the new link UI design.
Following on from this, I will then discuss how the current link interfaces within Gutenberg are created.
Finally, I will propose a route forward centred around creating a single unified component for link interfaces within Gutenberg.
Overview of existing "link" Components
The following components are already available within Gutenberg and are used for creating "link" interfaces.
URLInput
PostsandPagesas you type. URLs are not handled as search suggestions.packages/block-editor/src/components/url-inputlistboxARIA attrsURLPopover.LinkEditorand is only ever used in isolation withinpackages/block-library/src/button/edit.js. This component is low level. It does not provide a popover or a settings drawer. Therefore when used in isolation it will not provide the design for the new Link UI. Therefore it is ill suited as a wrapper component.URLPopover
URLInputandExternalLinkinternally.packages/block-editor/src/components/url-popoverURLInput, withURLInputprovinding the input and search suggestions andURLPopoverproviding the settings drawer, "selected" states and a popover in which to contain the UI.URLPopoveralso exposes the following sub components:URLPopover.LinkEditor
packages/block-editor/src/components/url-popover/link-editor.jsThis provides a simple wrapper around
URLInputto provide a<form>tag and aApplybutton.URLPopover.LinkViewer
packages/block-editor/src/components/url-popover/link-viewer.jsThis provides a simple style for "selected" links. It is a wrapper around
ExternalLinkand also provides an "Edit" button.How are link interfaces currently creating within Gutenberg?
As it stands the two existing components
URLInputandURLPopoverare largely low level components. Therefore, it is important to appreciate that in almost every case where a link interface is required within Gutenberg, these components are consumed and controlled by the parent component (viaprops) to create a bespoke interface.This happens each time a link UI is created.
Some good examples of this are:
URLPopoverAtLinkcomponent which wires togetherURLPopoverand (indirectly viaURLPopover.LinkEditor)URLInputto create a unified link interface.core/imageBlock'seditimplementation. You will note that the implementation is wiring together the low level components in such a way as to produce a unified link interface.MediaPlaceholdercomponent which has a bespoke link interface which does not even utiliseURLInput.core/social-linkBlock. Again this does not utiliseURLInput.What we can observe here is that each time an interface for adding links is required, the developer is currently required to wire together a bespoke implementation.
In short, there is currently no unified interface component for creating link UIs in Gutenberg.
Conclusion and Recommendation
Based on the evidence above, it appears that what is required is not extensive modification or refactoring of the existing
URL*components, but rather the creation of a single component which wires together the lower-level components to provide a unified link interface.Given that
URLInputis a low level component which is already in use, attempting to refactor this to be a wrapper around a more complex, fully unified Link UI would be complex, time-consuming and provide little or no benefit.Similarly,
URLPopoveris largely a visual component and should not be a candidate for managing state or a fully unified UI.Therefore, the most effective and expedient solution is to create a new component which unifies the existing components under a single interface.
By doing this we will provide the following benefits:
URLInputandURLPopovercomponents can be preserved and reused - no need for deprecations.URLInputandURLPopoverwill make these more flexible for future if/when required to create bespoke/highly customised link UIs that cannot be serviced by the unified component.The new component can be relased as "experimental" and then once accepted, it can gradually used to replace the existing bespoke usages of
URLPopoverandURLInputthereby standardising link intefaces across Gutenberg.This approach has already been trialled in this PR.
Appendix A: do we need to modify the existing components to deliver the new design?
The following changes are required to both components in order to realise the new design:
Changes to URLInput
Update rendering of suggestion items to add in more information about the suggestion (see Design) - this can be achieved by either:
URLInputdirectly (note: this means all existing implementations will inherit this change).URLInputto allow parent/consuming components to modify the rendered output of suggestion items (as per currentLinkControlPR).Update the
placeholderon the input - this is most easily achieved by exposing aplaceholderprop onURLInput.Fix to ensure that suggestions are hidden when the input is empty.
Design requires that when a URL is entered this is displayed as a search suggestion. Currently
URLInputwill ignore URLs when calling the function prop which fetches search suggestion data. This can be fixed by:updateSuggestionsmethod to detect URLs and immediately set thestate.suggestionsto be a single object representing the current input value (see the implementation inLinkControl)URLInputwhich conditionally enables URL handling in theupdateSuggestionsmethod. The parent component must then pass an appropriate handler based on the type of input (see the implementation in LinkControl)Changes to URLPopover
Given that it is mainly a wrapper component, it is unlikely that it would be useful to make changes to
URLPopover. Almost every example of a Link UI within Gutenberg consumesURLPopoveras a controlled component. All state management and customisation is handled outside ofURLPopover.The only major changes required to realise the new design would be:
Appendix B: Related Links