Sharing a box shadow by URL

How the whole state lives in the address bar and how to deep-link the generator.

The whole shadow in the address bar

Press Share link and the whole generator state, every layer, the box, the canvas and the box content, is written into a URL and copied for you. That is the entire sharing system: there is no save button, no short link service and no database. The URL is the shadow. Whoever opens it gets the generator in exactly the state you left it. The address bar stays clean while you work, because a bar full of numbers is hard to read and easy to copy by mistake; the state is only written to a link when you ask for one, and a link you open is loaded and then tidied away. Your work in progress is kept in your browser instead, so a reload resumes where you left off. The first version of this tool packed the same idea into a base64 blob; this one writes it in a form you can read and edit.

Why it lives after the hash

The state sits after the #, in the fragment identifier, rather than in a query string. RFC 3986, the standard that defines URLs, describes the fragment as allowing "indirect identification of a secondary resource by reference to a primary resource and additional identifying information". A shadow is a fine example of a secondary resource: the page is the generator, the fragment says which shadow to show in it. There is a more practical reason too, and MDN's introduction to URLs states it directly:

"It is worth noting that the part after the #, also known as the fragment identifier, is never sent to the server with the request."

MDN Web Docs, What is a URL?

Never sent to the server means the shadow you are working on stays in your browser: nothing to log, nothing to expire, and no privacy policy paragraph about it. It also means every share link points at one page for search engines, the home page, rather than at thousands of variations of it. And when a link is opened, tidying the fragment away with history.replaceState() neither reloads the page nor adds a history entry, so the back button still does what you expect.

The URL format

A link looks like this:

Share link
https://boxshadowgenerator.co.uk/#l=0,1,2,0,1b2340,.06,0;0,8,24,0,1b2340,.12,0&b=240,160,12,ffffff&c=light&t=Card

Four parameters, three of them optional after the first:

KeyContentsExample
lLayers, separated by ;. Each is x,y,blur,spread,hex,alpha,inset, with an optional eighth value 0 when the layer is hidden. Hex has no #; inset is 1 or 0.0,8,24,0,1b2340,.12,0
bBox: width,height,radius,hex, then optionally alpha and backdropBlur when they are not the defaults.240,160,12,ffffff,.35,12
cCanvas: light, dark, a hex colour, or img: followed by a bundled image name or an encoded image URL.img:ocean-floor
tThe box content, URL-encoded: plain text, or the small set of HTML the content editor allows. Omitted when it is the default.Card%20hover
aWhich layer is active, zero-based. Omitted when it is the first.2

Numbers keep at most two decimals and drop a leading zero, so an alpha of 0.12 is written .12. Anything the generator reads from a URL is validated and clamped before it is used: a blur of 900 becomes 200, a broken hex falls back to the default, an unknown canvas becomes light. A URL you have mistyped loads something sensible rather than nothing.

Sharing a link

Press Share link in the readout bar. On a desktop browser the URL is copied to the clipboard and the status line confirms it. On a phone, the browser's share sheet opens so you can send it straight to a message or a note; if the share sheet is not available the link is copied instead. Nothing else on the page writes to the address bar, so the link you get is always the one you asked for.

Links are stable. The format is versioned by its shape rather than a number, and the generator will keep reading this shape even if a later version adds keys. A link from today will open the same shadow in a year.

Because the format is readable, you can write links to the generator from anywhere: a design system's documentation, a code comment, a pull request description. Build the hash from the table above and append it to the home page URL. Every page in the examples gallery does this with its Open in generator button; the material elevation page, for instance, links to five different levels from one page. A minimal deep link needs only l:

HTML
<a href="https://boxshadowgenerator.co.uk/#l=0,4,12,0,000000,.15,0">
  Open this shadow in the generator
</a>

The box and canvas fall back to their defaults, a white 240 by 160 box on the light canvas, which is the right neutral for showing someone a shadow on its own.

What the URL does not carry

Three things stay out of the link on purpose. Saved presets are not included, because a library belongs in a file, not in every share. The selected output tab is not included, because the person you send a link to may want Tailwind where you wanted SCSS. And an image canvas that uses your own URL is included only as the URL, so if the picture is on your intranet the recipient sees the dark canvas instead. The bundled backgrounds are always available to everyone.

Frequently asked questions

How do I share a box shadow I made in the generator?

Press Share link in the readout. The current state is written into a URL and copied to your clipboard (on a phone, the share sheet opens). Anyone who opens the link sees the same layers, box, canvas and box content. The address bar itself stays clean while you work.

Is my shadow stored on a server when I share it?

No. The whole state is encoded in the part of the URL after the # sign, which browsers never send to the server. The link is the storage. There is nothing to expire and nothing to delete.

Can I edit the URL by hand?

Yes, the format is designed for it. Each layer is a comma separated list of x, y, blur, spread, hex colour, alpha and an inset flag; layers are separated by semicolons. Change a number, press Enter, and the generator reloads with the new value.

Sources

  1. IETF RFC 3986, Uniform Resource Identifier (URI): Generic Syntax, section 3.5 Fragment
  2. MDN Web Docs: What is a URL?
  3. MDN Web Docs: URL.hash
  4. MDN Web Docs: History.replaceState()