Inline audio player in Sanity.io rich text
How to use the Portable Text Editor's flexibility to insert dynamic content in the middle of paragraphs
We can host audio files in Sanity and plug them into paragraphs by adding custom types to the block.of array. You can see this in action in my Learn GROQ guide. Without further ado, here's the process:
Starting with the schema, we need to add the inlineAudio
schema type to our block content's of property (documentation on this property):
export default {
name: "contentBody",
title: 'Body of content',
type: 'array',
of: [
{
type: 'block',
of: [
{
name: 'inlineAudio',
type: 'file',
title: 'Inline audio player',
options: {
accept: 'audio/*',
},
},
],
},
{type: "image"}
]
}
This will allow us to add the "Inline audio player" element to our paragraph from the insert menu:
Now editors have the ability to add inline audio players to their content! ππ Let's cover how to render this in the front-end. Here's a portion of the component that renders the block content of my articles (I'm using React and the @sanity/block-content-to-react package):
import * as React from 'react'
import BlockContent from '@sanity/block-content-to-react'
import AudioPlayer from '../AudioPlayer'
const serializers = {
types: {
// Handler for the "inlineAudio" _type
inlineAudio: ({ node }) => {
// The component we use to render the actual player
return <AudioPlayer {...node} />
},
},
}
const ArticleBlockContent = (props) => {
return (
<BlockContent
blocks={props.blocks}
serializers={serializers}
/>
)
}
export default ArticleBlockContent
And here's the AudioPlayer
component that actually renders the data into an actionable button for users:
import * as React from 'react'
const AudioPlayer = (props) => {
// Used to store the audio element once instanciated
const [audioEl, setAudioEl] = React.useState()
if (!props.asset?._ref) {
return null
}
const { _ref: ref } = props.asset
// Example:
// From: file-ff7d1c2d7bd5ac367359d57f0319f5f458bc3c3d-m4a
// To: https://cdn.sanity.io/files/q2j8cwsg/production/ff7sfgc2d7bd5ac367359d57f0319f5f458bc3c3d.m4a?dl
const assetRefParts = ref.split('-') // ["file", "ff7...", "m4a"]
const id = assetRefParts[1] // "ff7..."
const format = assetRefParts[2] // "m4a"
const assetUrl = `https://cdn.sanity.io/files/${process.env.NEXT_PUBLIC_SANITY_PROJECT_ID}/${process.env.NEXT_PUBLIC_SANITY_DATASET}/${id}.${format}`
function playAudio() {
try {
if (!audioEl) {
const audio = new Audio(assetUrl)
setAudioEl(audio)
audio.play()
} else {
audioEl.play()
}
} catch (error) {}
}
return (
<button onClick={playAudio} aria-label="Play audio">
π
</button>
)
}
export default AudioPlayer
And that's it! There are many more interesting use cases of inline blocks, some of which I hope to cover in the future.
Reach me at meet@hdoro.dev or @hdorodev if you have any questions ;)
Sanity β build remarkable experiences at scale
Sanity Composable Content Cloud is the headless CMS that gives you (and your team) a content backend to drive websites and applications with modern tooling. It offers a real-time editing environment for content creators thatβs easy to configure but designed to be customized with JavaScript and React when needed. With the hosted document store, you query content freely and easily integrate with any framework or data source to distribute and enrich content.
Sanity scales from weekend projects to enterprise needs and is used by companies like Puma, AT&T, Burger King, Tata, and Figma.