Show downloadable file URL after PDF upload in Sanity

4 replies
Last updated: Jan 3, 2022
hey all! I have a file upload field that content editors can upload the pdf file. But is it possible to show the downloadable file url after the files are uploaded?
AI Update

Yes, absolutely! You can show the downloadable file URL after a PDF is uploaded. There are a couple of approaches you can take:

1. Display the URL in your frontend

When you query the file field with GROQ, you can get the URL like this:

*[_type == "yourDocumentType"] {
  "fileUrl": yourFileField.asset->url
}

Then in your frontend, you can display it as a download link. Important tip: Sanity files are hosted on a different origin, so the standard HTML download attribute won't work. Instead, use the ?dl query parameter:

<a href={fileUrl + '?dl'}>Download PDF</a>

The ?dl parameter tells Sanity's CDN to serve the file as a download instead of trying to display it in the browser.

2. Show the URL directly in Studio (for editors)

If you want content editors to see the download URL right in the Studio after uploading, you can create a custom input component. This would wrap the default file input and display the URL below it once a file is uploaded.

Here's a basic example:

import { FileInput } from 'sanity'

export default function FileWithUrl(props) {
  const fileUrl = props.value?.asset?._ref 
    ? `https://cdn.sanity.io/files/${projectId}/${dataset}/${props.value.asset._ref.replace('file-', '').replace('-pdf', '.pdf')}`
    : null

  return (
    <div>
      <FileInput {...props} />
      {fileUrl && (
        <div style={{marginTop: '1em'}}>
          <a href={fileUrl + '?dl'} target="_blank" rel="noopener noreferrer">
            Download: {fileUrl}
          </a>
        </div>
      )}
    </div>
  )
}

You can find more details in the Sanity documentation on file types and this community answer about adding downloadable file URLs.

Show original thread
4 replies
The idea is to get the accessible file URL so that users can go to sanity file url
Got it. So if I'm understanding correctly: you specifically just want to see a link that will lead to the file? Or do you want a link that opens the file in a separate tab? Either way, you'd use a custom input component below the file upload that is a) hidden if no file has been uploaded b) queries for the asset's url and c) renders some sort of React component. The following will give you a custom input component that opens a link to the asset in a separate tab. If you'd just like to render the url itself, you can change the render method to show the entire url instead.
//in your document schema
//don't forget to import UrlDownload.js at the top

{
      name: 'upload',
      title: 'Upload',
      type: 'object',
      fields: [
        {
          name: 'file',
          title: 'File',
          type: 'file'
        },
        {
          name: 'link',
          title: 'Link',
          type: 'string',
          hidden: ({parent}) => !parent?.file,
          inputComponent:UrlDownload
        }
      ]
   }

//UrlDownload.js

import React, { useEffect, useState } from 'react'
import sanityClient from "part:@sanity/base/client"

const client = sanityClient.withConfig({apiVersion: '2021-03-25'})

const UrlDownload = props => {
  const [link, setLink] = useState()

    useEffect(() => {
      const getLink = async () => {
        const assetLink = await client.fetch(`*[_id == $id][0].url`, { id: props.parent.file.asset._ref})
        setLink(assetLink)
      }

      getLink()
    }, [])

    return (
      <a 
        href={`${link}`} 
        target="_blank"
      >
        Download file
      </a>
    )
}

export default UrlDownload
Note that this does not currently write any data to the document, though.
Got it. So if I'm understanding correctly: you specifically just want to see a link that will lead to the file? Or do you want a link that opens the file in a separate tab? Either way, you'd use a custom input component below the file upload that is a) hidden if no file has been uploaded b) queries for the asset's url and c) renders some sort of React component. The following will give you a custom input component that opens a link to the asset in a separate tab. If you'd just like to render the url itself, you can change the render method to show the entire url instead.
//in your document schema

{
      name: 'upload',
      title: 'Upload',
      type: 'object',
      fields: [
        {
          name: 'file',
          title: 'File',
          type: 'file'
        },
        {
          name: 'link',
          title: 'Link',
          type: 'string',
          hidden: ({parent}) => !parent?.file,
          inputComponent:UrlDownload
        }
      ]
   }

//UrlDownload.js

import React, { useEffect, useState } from 'react'
import sanityClient from "part:@sanity/base/client"

const client = sanityClient.withConfig({apiVersion: '2021-03-25'})

const UrlDownload = props => {
  const [link, setLink] = useState()

    useEffect(() => {
      const getLink = async () => {
        const assetLink = await client.fetch(`*[_id == $id][0].url`, { id: props.parent.file.asset._ref})
        setLink(assetLink)
      }

      getLink()
    }, [])

    return (
      <a 
        href={`${link}`} 
        target="_blank"
      >
        Download file
      </a>
    )
}

export default UrlDownload
Note that this does not currently write any data to the document, though.
user M
Thank you very much. I just want to see the link to file.

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?