70 %

Toast is in Beta!Learn more →

Chris Biscardi

Tweetable Selections

I wanted a way to allow people to select some text on my website and share it, specifically to Twitter. I chose to do this using Twitter intents which allow me to set up a link that can be clicked that will send someone to Twitter and open the compose Tweet dialog.

I implemented a single React (well, Preact) component with useState to store the selected text and a fixed position area to display the text in when selected.

onselectionchange fires way too much (for every character you select) to update the message all the time, so I debounced the listener with a 200ms delay. In the listener we toString() the Selection object, which turns the object into a string of the selected text. We apply the listener in a useEffect and we're done.

JS
const Tweetable = () => {
const [tweetableText, setTweetableText] = useState();
useEffect(() => {
// event fires for every selection change
document.onselectionchange = debounce(() => {
// toString on the Selection object gives you the selected text
const text = document.getSelection().toString();
setTweetableText(text);
}, 200);
},[]);
return tweetableText ? (
<div
css={{
zIndex: 1,
position: "fixed",
top: "5px",
display: "flex",
flex: 1,
width: "100%",
background: "#10151e",
justifyContent: "center",
color: "#eef1f7",
borderBottom: "1px solid rgba(51,183,255,.21)"
}}
>
<div css={{ maxWidth: 400, display: "flex", flexDirection: "column" }}>
<p css={{ paddingTop: "1rem" }}>{tweetableText}</p>
<a
href={
"https://twitter.com/intent/tweet?text=" +
encodeURI(tweetableText + " " + window.location.href)
}
css={{ color: "#1DA1F2", alignSelf: "flex-end", padding: "1rem" }}
>
Tweet this
</a>
</div>
</div>
) : null;
};

and the debounce function I used:

JS
const debounce = (func, wait) => {
let timeout;
return function executedFunction(...args) {
const later = () => {
timeout = null;
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
};