Skip to main content

Link Preview

Enable sighted users to preview content behind a link.

Features

  • Controlled or uncontrolled
  • Ignored by screen readers
  • Custom open and close delay support
  • Positioning and alignment customization

⚠️ The Link Preview is only intended to be used with a mouse or other pointing device. It doesn't respond to touch events, and the preview content cannot be accessed via the keyboard. On touch devices, the link will be followed immediately. As it is not accessible to all users, the preview should not contain vital information.

Anatomy

  • Trigger: The element that opens the link preview on hover.
  • Content: The element containing the content for the link preview.
  • Arrow: An optional arrow component

Usage

Create a link preview using the createLinkPreview builder function.

    <script lang="ts">
  import { createLinkPreview, melt } from '@melt-ui/svelte'
  const {
    elements: { trigger, content, arrow }
  } = createLinkPreview()
</script>
	
    <script lang="ts">
  import { createLinkPreview, melt } from '@melt-ui/svelte'
  const {
    elements: { trigger, content, arrow }
  } = createLinkPreview()
</script>
	

Then you can use the trigger, content, and arrow to construct a link preview. A high level example of how to structure the link preview is shown below.

    <script lang="ts">
  import { createLinkPreview, melt } from '@melt-ui/svelte'
  const {
    elements: { trigger, content, arrow }
  } = createLinkPreview()
</script>
 
<button use:melt={$trigger}>Hover Me</button>
 
<div use:melt={$content}>
  <div>I am content inside the link preview</div>
  <div use:melt={$arrow} />
</div>
	
    <script lang="ts">
  import { createLinkPreview, melt } from '@melt-ui/svelte'
  const {
    elements: { trigger, content, arrow }
  } = createLinkPreview()
</script>
 
<button {...$trigger} use:trigger>Hover Me</button>
 
<div {...$content} use:content>
  <div>I am content inside the link preview</div>
  <div {...$arrow} use:arrow />
</div>
	

It's also possible to use Svelte Transitions, as demonstrated in the example at the top of this page.

Focus handling

By default the link preview will be shown when focused by the keyboard (or more specifically if :focus-visible would apply), and hide on blur.

You can disable this functionality by listening to and cancelling the custom m-focus and m-blur events.

    <button
  use:melt={$trigger}
  on:m-focus={(e) => {
    e.preventDefault()
  }}
  on:m-blur={(e) => {
    e.preventDefault()
  }}>
  Hover Me
</button>
	
    <button
  {...$trigger} use:trigger
  on:m-focus={(e) => {
    e.preventDefault()
  }}
  on:m-blur={(e) => {
    e.preventDefault()
  }}>
  Hover Me
</button>
	

API Reference

createLinkPreview

The builder function used to create the link preview component.

Props

Prop Default Type / Description
openDelay 700
number

The delay in milliseconds before the link preview opens.

closeDelay 300
number

The delay in milliseconds before the link preview closes.

positioning placement: 'bottom'

A configuration object which determines how the floating element is positioned relative to the trigger.

arrowSize 8
number

The size of the arrow which points to the trigger in pixels.

closeOnOutsideClick true
boolean

Whether or not to close the link preview when the user clicks outside of it.

escapeBehavior 'close'
'close' | 'ignore' | 'defer-otherwise-close' | 'defer-otherwise-ignore'

Defines how the link preview reacts when the Escape key is pressed.

  • close: Closes the link preview immediately.
  • ignore: Prevents the link preview from closing and also blocks the parent element from closing in response to the Escape key.
  • defer-otherwise-close: Delegates the action to the parent element. If no parent is found, it closes the element.
  • defer-otherwise-ignore: Delegates the action to the parent element. If no parent is found, nothing is done.
  • preventTextSelectionOverflow true
    boolean

    Whether to prevent text selection overflowing the link preview when it is the top layer.

    forceVisible false
    boolean

    Whether or not to force the link preview to always be visible. This is useful for custom transitions and animations using conditional blocks.

    portal body
    string | HTMLElement | null

    The element or selector to render the link preview into. Nested floating elements are automatically rendered into their own portal if not specified. Pass in null to disable portalling. Pass in undefined to use parent portal.

    defaultOpen false
    boolean

    Whether the link preview is open by default or not.

    open -
    Writable<boolean>

    A writable store that controls whether or not the link preview is open.

    See Bring Your Own Store

    onOpenChange -
    ChangeFn<boolean>

    A callback called when the value of the open store should be changed.

    See Change Functions

    ids -
    Record<'trigger' | 'content', string>

    Override the internally generated ids for the elements.

    Elements

    Element Description

    The builder store used to create the link preview trigger.

    The builder store used to create the link preview content.

    The builder store used to create the link preview arrow.

    States

    State Description
    open

    A writable store with the open state of the link preview.

    Options

    Option Description
    openDelay

    The delay in milliseconds before the link preview opens.

    closeDelay

    The delay in milliseconds before the link preview closes.

    positioning

    A configuration object which determines how the floating element is positioned relative to the trigger.

    arrowSize

    The size of the arrow which points to the trigger in pixels.

    closeOnOutsideClick

    Whether or not to close the link preview when the user clicks outside of it.

    escapeBehavior

    Defines how the link preview reacts when the Escape key is pressed.

  • close: Closes the link preview immediately.
  • ignore: Prevents the link preview from closing and also blocks the parent element from closing in response to the Escape key.
  • defer-otherwise-close: Delegates the action to the parent element. If no parent is found, it closes the element.
  • defer-otherwise-ignore: Delegates the action to the parent element. If no parent is found, nothing is done.
  • preventTextSelectionOverflow

    Whether to prevent text selection overflowing the link preview when it is the top layer.

    forceVisible

    Whether or not to force the link preview to always be visible. This is useful for custom transitions and animations using conditional blocks.

    portal

    The element or selector to render the link preview into. Nested floating elements are automatically rendered into their own portal if not specified. Pass in null to disable portalling. Pass in undefined to use parent portal.

    IDs

    Option Description
    trigger

    The writable store that represents the id of the trigger element.

    content

    The writable store that represents the id of the content element.

    trigger

    The link preview trigger element.

    Data Attributes

    Data Attribute Value
    [data-state]

    'open' | 'closed'

    [data-melt-link-preview-trigger]

    Present on all trigger elements.

    Custom Events

    Event Value
    m-pointerenter (e: ) => void
    m-pointerleave (e: ) => void
    m-focus (e: ) => void
    m-blur (e: ) => void

    content

    The content displayed in the linkpreview

    Data Attributes

    Data Attribute Value
    [data-side]

    'top' | 'right' | 'bottom' | 'left'

    [data-align]

    'start' | 'center' | 'end'

    [data-state]

    'open' | 'closed'

    [data-melt-link-preview-content]

    Present on all content elements.

    Custom Events

    Event Value
    m-pointerdown (e: ) => void
    m-pointerenter (e: ) => void
    m-pointerleave (e: ) => void
    m-focusout (e: ) => void

    arrow

    An optional arrow element which points to the menu's trigger.

    Data Attributes

    Data Attribute Value
    [data-side]

    'top' | 'right' | 'bottom' | 'left'

    [data-arrow]

    'true'

    [data-melt-link-preview-arrow]

    Present on all arrow elements.

    Accessibility

    The link preview is only intended to be used with a mouse or other pointing device. The preview's content element cannot be accessed via the keyboard and is not exposed to screen readers. As a result the preview should not contain content that is otherwise not visible elsewhere.

    Comparison with Tooltip

    The link preview is similar to the Tooltip builder, as both have floating contents that initially are hidden, and appear when hovering over the trigger, or focusing it with the keyboard.

    There are some key differences though. A Tooltip's content should not have any clickable elements inside it, while a Link Preview's content can contain them. Also, a Tooltip's content is exposed to screen readers, while a Link Preview's content is not. Keep this in mind when choosing which builder to use, as this has implications for accessibility.