Inline Spoiler Shortcode
Adds a [spoiler] shortcode that blurs a word or sentence until the reader clicks it or presses Enter or Space, and keeps the hidden text from screen readers until it is revealed.
Opens WPIDE on
Code
// What screen readers announce (and the tooltip shows) before the spoiler is revealed.
$wpide_spoiler_label = 'Spoiler, select to reveal';
$wpide_spoiler_script = function () {
?>
<script>
( function () {
function reveal( spoiler ) {
spoiler.classList.add( 'is-revealed' );
[ 'role', 'aria-label', 'aria-expanded', 'title' ].forEach( function ( name ) {
spoiler.removeAttribute( name );
} );
spoiler.setAttribute( 'tabindex', '-1' );
var text = spoiler.querySelector( '.wpide-spoiler__text' );
if ( text ) {
text.removeAttribute( 'inert' );
}
}
function find( target ) {
return target && target.closest ? target.closest( '.wpide-spoiler:not(.is-revealed)' ) : null;
}
document.addEventListener( 'click', function ( event ) {
var spoiler = find( event.target );
if ( spoiler ) {
event.preventDefault();
reveal( spoiler );
}
} );
document.addEventListener( 'keydown', function ( event ) {
var spoiler = find( event.target );
if ( spoiler && ( event.key === 'Enter' || event.key === ' ' ) ) {
event.preventDefault();
reveal( spoiler );
}
} );
} )();
</script>
<?php
};
add_shortcode( 'spoiler', function ( $atts, $content = '' ) use ( $wpide_spoiler_label, $wpide_spoiler_script ) {
static $assets_added = false;
$atts = shortcode_atts( array( 'label' => $wpide_spoiler_label ), $atts, 'spoiler' );
$content = trim( do_shortcode( wp_kses_post( (string) $content ) ) );
if ( '' === $content ) {
return '';
}
// Feed readers do not run scripts or keep styles, so feeds only get the label.
if ( is_feed() ) {
return '[' . esc_html( $atts['label'] ) . ']';
}
$style = '';
if ( ! $assets_added ) {
$assets_added = true;
add_action( 'wp_footer', $wpide_spoiler_script );
// Printed with the first spoiler so the text is never visible before the styles load.
$style = '<style>'
. '.wpide-spoiler{border-radius:3px;background:rgba(128,128,128,.25);cursor:pointer;}'
. '.wpide-spoiler__text{filter:blur(.3em);-webkit-user-select:none;user-select:none;transition:filter .2s ease;}'
. '.wpide-spoiler:focus-visible{outline:2px solid currentColor;outline-offset:2px;}'
. '.wpide-spoiler:focus .wpide-spoiler__text,.wpide-spoiler.is-revealed .wpide-spoiler__text{filter:none;-webkit-user-select:auto;user-select:auto;}'
. '.wpide-spoiler.is-revealed{background:none;cursor:auto;outline:none;}'
. '@media (prefers-reduced-motion:reduce){.wpide-spoiler__text{transition:none;}}'
. '</style>';
}
return $style . sprintf(
'<span class="wpide-spoiler" role="button" tabindex="0" aria-expanded="false" aria-label="%1$s" title="%1$s"><span class="wpide-spoiler__text" inert>%2$s</span></span>',
esc_attr( $atts['label'] ),
$content
);
} );
Notes
Example: The killer was [spoiler]the butler[/spoiler]. Change what screen readers announce with [spoiler label="Ending spoiler"]. Feeds show only the label. Without JavaScript the text shows while the spoiler has keyboard focus.
How to add this snippet
- Install WPIDE on your WordPress site (it is free) and open Code Snippets.
- Use snippet above adds it from the library in one click. Or copy the code into a new snippet with the same code type.
- It is added inactive: review the code and settings, then switch it on.