A declarative Web Share API
Tags: html, markup, declarative, webshare
Published: 2020-10-09 16:18:51

---
title: A declarative Web Share API
published: true
date: 2020-09-15 10:17:19 UTC
tags: html,markup,declarative,webshare
canonical_url: https://adactio.com/journal/17398
---

[I’ve written about the Web Share API before](https://adactio.com/journal/15972). It’s a handy little bit of JavaScript that—if supported—brings up a system-level way of sharing a page. Seeing as it probably won’t be long before [we won’t be able to see full URLs in browsers anymore](https://adactio.com/journal/17285), it’s going to fall on us as site owners to provide this kind of fundamental access.

Right now [the Web Share API](https://www.w3.org/TR/web-share/) exists entirely in JavaScript. There are quite a few browser APIs like that, and it always feels like a bit of a shame to me. Ideally there should be a JavaScript API _and_ a declarative option, even if the declarative option isn’t as powerful.

Take form validation. To cover the most common use cases, you probably only need to use declarative markup like `input type="email"` or the `required` attribute. But if your use case gets a bit more complicated, you can reach for the [Constraint Validation API](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#the-constraint-validation-api) in JavaScript.

I like that pattern. I wish it were an option for JavaScript-only APIs. Take [the Geolocation API](https://www.w3.org/TR/geolocation-API/), for example. Right now it’s only available through JavaScript. But what if there were an `input type="geolocation"` ? It wouldn’t cover all use cases, but it wouldn’t have to. For the simple case of getting someone’s location (like getting someone’s email or telephone number), it would do. For anything more complex than that, that’s what the JavaScript API is for.

I was reminded of this recently when [Ada Rose Cannon tweeted](https://twitter.com/Lady_Ada_King/status/1296844595414933508):

> It really feels like there should be a semantic version of the share API, like a mailto: link

I think she’s absolutely right. The Web Share API has one primary use case: let the user share the current page. If that use case could be met in a declarative way, then it would have a lower barrier to entry. And for anyone who needs to do something more complicated, that’s what the JavaScript API is for.

But [Pete LePage asked](https://twitter.com/petele/status/1296848675726073856):

> How would you feature detect for it?

Good question. With the JavaScript API you can do feature detection—if the API isn’t supported you can either bail or provide your own implementation.

There a few different ways of extending HTML that allow you to provide a fallback for non-supporting browsers.

You could mint a new element with a content model that says “Browsers, if you _do_ support this element, ignore everything inside the opening and closing tags.” That’s the way that the `canvas` element works. It’s the same for `audio` and `video`—they ignore everything inside them that isn’t a `source` element. So developers can provide a fallback within the opening and closing tags.

But forging a new element would be overkill for something like the Web Share API (or Geolocation). There are more subtle ways of extending HTML that I’ve already alluded to.

Making a new element is a lot of work. Making a new attribute could also be a lot of work. But making a new attribute _value_ might hit the sweet spot. That’s why I suggested something like `input type="geolocation"` for the declarative version of the Geolocation API. There’s prior art here; this is how we got input types for email, url, tel, color, date, etc. The key piece of behaviour is that non-supporting browsers will treat any value they don’t understand as “text”.

I don’t think there should be `input type="share"`. The action of sharing isn’t an input. But I do think we could find an existing HTML element with an attribute that currently accepts a list of possible values. Adding one more value to that list feels like an inexpensive move.

[Here’s what I suggested](https://adactio.com/notes/17326):

> <button type=”share” value=”title,text”>
> 
> For non-supporting browsers, it’s a regular button and needs polyfilling, no different to the situation with the JavaScript API. But if supported, no JS needed?

The `type` attribute of [the `button` element](https://html.spec.whatwg.org/multipage/form-elements.html#the-button-element) currently accepts three possible values: “submit”, “reset”, or “button”. If you give it any other value, it will behave as though you gave it a `type` of “submit” or “button” (depending on whether it’s in a form or not) …just like an unknown `type` value on an `input` element will behave like “text”.

If a browser supports `button type="share”`, then when the user clicks on it, the browser can go “Right, I’m handing over to the operating system now.”

There’s still the question of how to pass data to the operating system on what gets shared. Currently the JavaScript API allows you to share any combination of URL, text, and description.

Initially I was thinking that the `value` attribute could be used to store this data in some kind of key/value pairing, but the more I think about it, the more I think that this aspect should remain the exclusive domain of the JavaScript API. The declarative version could grab the current URL and the value of the page’s `title` element and pass those along to the operating system. If you need anything more complex than that, use the JavaScript API.

So what I’m proposing is:

```
<button type="share">

```

That’s it.

But how would you test for browser support? The same way as you can currently [test for supported `input` types](https://html5forwebdesigners.com/forms/#testing). Make use of the fact that an element’s attribute value and an element’s _property_ value (which 99% of the time are the same), will be different if the attribute value isn’t supported:

```
var testButton = document.createElement("button");
testButton.setAttribute("type","share");
if (testButton.type != "share") {
// polyfill
}

```

So that’s my modest proposal. Extend the list of possible values for the `type` attribute on the `button` element to include “share” (or something like that). In supporting browsers, it triggers a very bare-bones handover to the OS (the current URL and the current page title). In non-supporting browsers, it behaves like a button currently behaves.