# A Link Preview Component for SvelteKit (Part 1)

<details data-node-type="hn-details-summary"><summary>TL;DR of this article</summary><div data-type="detailsContent">We introduce the OpenGraph Protocol and the basic use case supported by our component. We create a basic SvelteKit and embed a TypeScript compatible component inside</div></details>

One of the glories of the Hypertextual medium is the ability to enrich one's messages with links. Indeed, Hyperlinks (to give their proper address) to websites, images, video and such are the very *fabric* of the Internet, although not without drawbacks.

Sometimes, links may lead to content a reader is already familiar with, or does not wish to consume, and as such it is not surprising that one might wish to provide a *preview* of the object to which a link pertains.

Sadly, this is not a native faculty possessed by The Internet at large, which may surprise given the common appearance of previews in apps such as Slack:

![A Link Preview for the GentleHacker article "The New Year, for ADHD Sorcerers", displayed in Slack.](https://cdn.hashnode.com/res/hashnode/image/upload/v1705973393435/f9e30346-5d11-485c-8e8e-cd25c12c78cb.png align="left")

---

# How, then, are link previews generated?

You might suppose the process involves using a headless browser to take screenshots, or interrogating the HTML to guess the details. Thankfully, this is not the case; often, the required information is supplied via the [Open Graph Protocol](https://ogp.me/) which

> enables any web page to become a rich object in a social graph.

A simple, dependency-free protocol defined under the [Open Web Foundation Agreement, Version 0.9](https://openwebfoundation.org/legal/the-0-9-agreements---necessary-claims), the Open Graph Protocol (henceforth the OGP) allows page authors to mark up specific metadata to help other sites provide information about the linked content.

<div data-node-type="callout">
<div data-node-type="callout-emoji">🎩</div>
<div data-node-type="callout-text"><strong>Content</strong> is the key word here; remember that HTTP provides a means of retrieving data <em>in general; </em>it's not specifically limited to web pages. Any resource can be transmitted over HTTP including images, video, and other data constructs. The OGP makes provisions for quite a few data types!</div>
</div>

This, I'm sure you'll agree, is much easier then finangeling a headless browser. Let us make use of it!

# The makeup of the Metadata

The OGP is a fairly simple affair, relying on `<meta>` tags embedded into the `<head>` tag of a response. Which is appropriate, as this is indeed [what said tag is for](https://www.w3schools.com/tags/tag_head.asp).

<div data-node-type="callout">
<div data-node-type="callout-emoji">🛎</div>
<div data-node-type="callout-text">It is important to note that we are not referring to the HTTP Headers here. The <code>&lt;head&gt;</code> tag is, confusingly, part of the body of a HTTP response.</div>
</div>

Open Graph describes resources as *objects* and provides some common properties from which to obtain information. Each property name starts with `og:` to indicate it belongs to the Open Graph namespace. Four properties are required, and seven are considered optional (but generally recommended).

## Required Properties

`og:title` has the object's title as it should be displayed when embedded.  
`og:type` details what type of object this page contains (such as `website` or `image`).  
`og:image` is a URL to an image which should be used as part of the preview.  
`og:url` provides the *canonical* URL for the object in question.

<div data-node-type="callout">
<div data-node-type="callout-emoji">👁‍🗨️</div>
<div data-node-type="callout-text">A <em>canonical </em>URL typically means one that provides a fixed, permanent reference to the primary version of some resource; The OGP uses it to mean a permanent, unique URL for a piece of content.</div>
</div>

This is what the Required Properties might look like for a site detailing Professor Eliza Williams' research into Difference Engine Temperature Compensators:

%[https://snappify.com/view/36dfac00-1f96-4e74-9326-6a5f28e62892] 

## Optional Properties

Provisions are also made for additional information; Knowledge is Power after all.

`og:description` is a one-to-two sentence description of the object in question.  
`og:site_name` gives the name of the larger website an object belongs to, if any.  
`og:locale` indicates which linguistic locale the tags are marked up in.  
`og:locale_alternate` offers an array of other locales available.  
`og:determiner` supplies the word which should fall before this object's title in a sentence ("*the*", "*an*" et al).

`og:audio` provides a URL to an audio file to 'accompany' this object.  
`og:video` advises a URL to a video file that 'complements' the object.

(Mostly straightforward, although you might be curious why audio files *accompany* but video files *complement*, and what, precisely, those verbs are intended to convey. I am also curious; if you know, I beseech you to leave a comment.)

Professor Eliza is a Modern Woman, so her site includes all of the above:

%[https://snappify.com/view/18a02c80-cf99-4f7b-ac55-89f6247ff3a4] 

<div data-node-type="callout">
<div data-node-type="callout-emoji">🛎</div>
<div data-node-type="callout-text">You might notice the repeated instance of <code>og:locale_alternate</code>. This is how arrays of data are encoded in the Open Graph protocol. You may find this odd; I agree. And yet.</div>
</div>

## Further Types of Object

The `website` type is perhaps the most common object embedded with the OGP, but the protocol includes many other object. These objects, in turn, have their own structured properties, namespaced as `og:type_of_object`. For instance, the `image` type makes the dimensions of an image available as `og:image:width` and `og:image:height`.

The full list is available [at the source](https://ogp.me/); We shaln't discuss it here in the interests of brevity.

---

# So what shall we build?

Let us build a link preview component for [SvelteKit](https://kit.svelte.dev/) which takes a URL and renders for us a lovely preview of the associated content, using the OGP metadata embedded therein.

For ease of use, we shall use TypeScript to help ensure correct data management. The completed component should be pleasing to the eye and behave well different resolutions.

We shall, at first, restrict ourselves to displaying only the basic metadata; Whilst the support for extra content types is robust, we do not, for the first attempt, need the extra complexity.

We shall also make an assumption which, while unkind, is not unfair. Developers are only human and may, at times, make mistakes, causing them to omit some or all of the required fields. As such, our component will *not* assume that the provided metadata is correct.

**Our Requirements are thus:**

* Display the basic image along with the title, and provide a link to the canonical URL
    
* Exhibit a responsive, fetching design
    
* Allow for incorrect metadata
    
* Provide developer friendly interface, inc. Typescript.
    

---

In future entries, we shall endevour to provide more useful default behaviour; enrich our support for divers content types, and package our component as an installable library which can be distributed at will. Such fancies, however, shall have to wait; For now, our target is a component that will look like the following when used in situ:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1706501703848/4231c078-76d9-476b-8a63-d4251be09c57.png align="center")

That looks rather fetching, don't you think?

---

# Getting Ready.

To begin, I've created a basic [SvelteKit](https://kit.svelte.dev/) site posessing an assortment of pages, each professing a different kind of OpenGraph object. The site uses images from [UnSplash](https://unsplash.com/) as preview images and is otherwise fairly unremarkable.

Having said that, the index will serve as a gallery showing how the finished component will render for diverse types, so it may prove of some interest. You can find it at [https://ogcomponentdemo.gentlehacker.codes/](https://ogcomponentdemo.gentlehacker.codes/) and the source lives at [https://github.com/DylanLacey/OGComponentDemo](https://github.com/DylanLacey/OGComponentDemo).

---

# Onwards!

In my next missive, we shall implement the basis of our component, and briefly discuss the correct architecture of SvelteKit applications.
