Spoiler

The Spoiler component automatically collapses content that exceeds a specified height, providing a show/hide toggle to reveal the full content.

Basic Usage

Set maxHeight to reveal a preview of long copy while the rest stays accessible behind the built-in toggle.

Loading demo…

import

 

{

 

Block

,

 

Card

,

 

Spoiler

,

 

Text

 

}

 

from

 

'@platform-blocks/react-ui-library'

;

 

const

paragraphs

=

 

[

  

'Spoilers collapse long sections of copy while keeping the content accessible to screen readers and keyboard users.'

,

  

'Use them for optional detail or secondary information that might distract from a primary task. They expand inline, so the surrounding layout stays stable.'

,

]

;

 

export

 

function

 

Demo

(

)

 

{

  

return

 

(

    

<Card

 

p

=

"md"

>

      

<Block

>

        

<Text

 

size

=

"sm"

 

color

=

"secondary"

>

          

Keep

the initial height short to hint that more detail is available without overwhelming the layout

.

        

</Text

>

        

<Spoiler

 

maxHeight

=

{

96

}

>

          

<Block

>

            

{

paragraphs

.

map

(

(

paragraph

)

 

=>

 

(

              

<Text

 

key

=

{

paragraph

}

 

size

=

"sm"

>

                

{

paragraph

}

              

</Text

>

            

)

)

}

          

</Block

>

        

</Spoiler

>

      

</Block

>

    

</Card

>

  

)

;

}

Initial State

Flip the initiallyOpen prop to choose whether content renders expanded on mount or waits for user interaction.

Loading demo…

import

 

{

 

Block

,

 

Card

,

 

Spoiler

,

 

Text

 

}

 

from

 

'@platform-blocks/react-ui-library'

;

 

const

examples

=

 

[

  

{

    key

:

 

'open'

,

    label

:

 

'Initially open'

,

    description

:

      

'Starts expanded by default so the reader sees the full content on first render.'

,

    props

:

 

{

initiallyOpen

:

 

true

 

}

,

  

}

,

  

{

    key

:

 

'closed'

,

    label

:

 

'Initially closed'

,

    description

:

      

'Keeps the section compact to emphasize surrounding UI until the user opts in.'

,

    props

:

 

{

}

,

  

}

,

]

;

 

const

bodyCopy

=

  

'Vivamus fermentum orci eget tortor facilisis, eu egestas eros maximus. Fusce vitae semper libero. Pellentesque habitant morbi tristique senectus et netus.'

;

 

export

 

function

 

Demo

(

)

 

{

  

return

 

(

    

<Card

 

p

=

"md"

>

      

<Block

>

        

<Text

 

size

=

"sm"

 

color

=

"secondary"

>

          

Control

whether the content renders expanded on mount or waits

for

user input

.

 

Both

states remain accessible to assistive tech

.

        

</Text

>

        

<Block

>

          

{

examples

.

map

(

(

example

)

 

=>

 

(

            

<Block

 

key

=

{

example

.

key

}

>

              

<Text

 

size

=

"xs"

 

color

=

"secondary"

>

                

{

example

.

label

}

              

</Text

>

              

<Spoiler

 

maxHeight

=

{

72

}

 

{

.

.

.

example

.

props

}

>

                

<Text

 

size

=

"sm"

>

{

bodyCopy

}

</Text

>

              

</Spoiler

>

              

<Text

 

size

=

"xs"

 

color

=

"muted"

>

                

{

example

.

description

}

              

</Text

>

            

</Block

>

          

)

)

}

        

</Block

>

      

</Block

>

    

</Card

>

  

)

;

}

Max Heights

Dial the maxHeight value up or down to control how much content stays visible before the toggle appears.

Loading demo…

import

 

{

 

Block

,

 

Card

,

 

Spoiler

,

 

Text

 

}

 

from

 

'@platform-blocks/react-ui-library'

;

 

const

longText

=

  

'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Integer tincidunt condimentum risus, sit amet cursus massa fermentum non.'

;

 

const

examples

=

 

[

  

{

key

:

 

'small'

,

label

:

 

'60px height'

,

maxHeight

:

 

60

 

}

,

  

{

key

:

 

'medium'

,

label

:

 

'100px height'

,

maxHeight

:

 

100

 

}

,

  

{

key

:

 

'large'

,

label

:

 

'150px height'

,

maxHeight

:

 

150

 

}

,

]

;

 

export

 

function

 

Demo

(

)

 

{

  

return

 

(

    

<Card

 

p

=

"md"

>

      

<Block

>

        

<Text

 

size

=

"sm"

 

color

=

"secondary"

>

          

Adjust

maxHeight to control how much text stays visible before the rest collapses behind the toggle

.

        

</Text

>

        

<Block

>

          

{

examples

.

map

(

(

example

)

 

=>

 

(

            

<Block

 

key

=

{

example

.

key

}

>

              

<Text

 

size

=

"xs"

 

color

=

"secondary"

>

                

{

example

.

label

}

              

</Text

>

              

<Spoiler

 

maxHeight

=

{

example

.

maxHeight

}

>

                

<Text

 

size

=

"sm"

>

{

longText

}

</Text

>

              

</Spoiler

>

            

</Block

>

          

)

)

}

        

</Block

>

      

</Block

>

    

</Card

>

  

)

;

}

Custom Control

Use the renderControl callback alongside opened and onToggle to drive expansion with your own button or analytics hooks.

Loading demo…

import

 

{

useState

}

 

from

 

'react'

;

 

import

 

{

 

Block

,

 

Button

,

 

Card

,

 

Spoiler

,

 

Text

 

}

 

from

 

'@platform-blocks/react-ui-library'

;

 

export

 

function

 

Demo

(

)

 

{

  

const

 

[

isOpen

,

setIsOpen

]

 

=

 

useState

(

false

)

;

 

  

return

 

(

    

<Card

 

p

=

"md"

>

      

<Block

>

        

<Text

 

size

=

"sm"

 

color

=

"secondary"

>

          

Drive

the spoiler state yourself to sync analytics or a sibling component

.

 

Use

renderControl when you need a bespoke trigger

.

        

</Text

>

        

<Spoiler

          

maxHeight

=

{

80

}

          

opened

=

{

isOpen

}

          

onToggle

=

{

setIsOpen

}

          

renderControl

=

{

(

{

opened

,

toggle

}

)

 

=>

 

(

            

<Button

 

size

=

"xs"

 

variant

=

"outline"

 

onPress

=

{

toggle

}

>

              

{

opened

?

 

'Collapse content'

 

:

 

'Expand content'

}

            

</Button

>

          

)

}

        

>

          

<Block

>

            

<Text

 

size

=

"sm"

>

Open

state

:

 

{

String

(

isOpen

)

}

</Text

>

            

<Text

 

size

=

"sm"

>

You

can render

any

 

React

node as the control

.

</Text

>

            

<Text

 

size

=

"sm"

>

              

Because

the component is controlled

,

you can track expansion analytics or sync other

UI

elements when content is revealed

.

            

</Text

>

          

</Block

>

        

</Spoiler

>

      

</Block

>

    

</Card

>

  

)

;

}

Control customization

controlProps accepts any <Text> props (ff, weight, tracking, uppercase, size, color) and applies them to the show/hide control text — useful when the rest of your design system uses a particular weight or tracking style.

Loading demo…

import

 

{

 

Block

,

 

Spoiler

,

 

Text

 

}

 

from

 

'@platform-blocks/react-ui-library'

;

 

const

longText

=

  

'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.'

;

 

export

 

function

 

Demo

(

)

 

{

  

return

 

(

    

<Block

>

      

<Block

>

        

<Text

 

size

=

"sm"

 

color

=

"muted"

>

Default

control

</Text

>

        

<Spoiler

 

maxHeight

=

{

60

}

>

          

<Text

>

{

longText

}

</Text

>

        

</Spoiler

>

      

</Block

>

 

      

<Block

>

        

<Text

 

size

=

"sm"

 

color

=

"muted"

>

          

Uppercase

tracked control

        

</Text

>

        

<Spoiler

          

maxHeight

=

{

60

}

          

showLabel

=

"Read more"

          

hideLabel

=

"Hide"

          

controlProps

=

{

{

uppercase

:

 

true

,

tracking

:

 

1.5

,

weight

:

 

'700'

,

size

:

 

'xs'

 

}

}

        

>

          

<Text

>

{

longText

}

</Text

>

        

</Spoiler

>

      

</Block

>

 

      

<Block

>

        

<Text

 

size

=

"sm"

 

color

=

"muted"

>

          

Monospace

control

        

</Text

>

        

<Spoiler

          

maxHeight

=

{

60

}

          

showLabel

=

"$ expand"

          

hideLabel

=

"$ collapse"

          

controlProps

=

{

{

ff

:

 

'monospace'

,

weight

:

 

'600'

 

}

}

        

>

          

<Text

>

{

longText

}

</Text

>

        

</Spoiler

>

      

</Block

>

    

</Block

>

  

)

;

}

Newspaper

Combine imagery with long-form copy to mimic a newspaper-style reveal where the reader can expand to see the full story.

Loading demo…

import

 

{

 

Card

,

 

Spoiler

,

 

Text

 

}

 

from

 

'@platform-blocks/react-ui-library'

;

import

 

{

 

Image

,

 

Platform

,

 

View

 

}

 

from

 

'react-native'

;

 

const

paragraphs

=

 

[

  

'The coastal morning edition arrived with stories about record tides and neighborhoods working together to reinforce their seawalls. Photographers captured gulls darting between the waves as volunteers stacked sandbags along the promenade.'

,

  

'Hidden inside the fold was a feature about an amateur archivist who discovered a crate of glass negatives documenting life on the waterfront a century ago. Each plate is being digitized so classrooms can study the evolution of the shoreline.'

,

  

'City gardeners are also experimenting with hardy dune grasses to keep wind-swept sand in place during the colder months. The pilot plots stretch for blocks and bring a warm beige tone to an otherwise grey season.'

,

]

;

 

export

 

function

 

Demo

(

)

 

{

  

const

isWeb

=

 

Platform

.

OS

 

===

 

'web'

;

 

  

return

 

(

    

<Card

 

p

=

"md"

>

      

<Spoiler

 

maxHeight

=

{

isWeb

?

 

220

 

:

 

260

}

>

        

<View

 

style

=

{

{

flexDirection

:

isWeb

?

 

'row'

 

:

 

'column'

 

}

}

>

          

<Image

            

source

=

{

require

(

'../../../../assets/images/scene-ocean.png'

)

}

            

style

=

{

{

width

:

 

180

,

height

:

 

180

,

borderRadius

:

 

12

,

marginRight

:

isWeb

?

 

16

 

:

 

0

,

marginBottom

:

isWeb

?

 

0

 

:

 

12

 

}

}

          

/>

          

<View

 

style

=

{

{

flex

:

 

1

,

marginTop

:

isWeb

?

 

0

 

:

 

8

 

}

}

>

            

{

paragraphs

.

map

(

(

paragraph

)

 

=>

 

(

              

<Text

 

key

=

{

paragraph

}

 

size

=

"lg"

 

style

=

{

{

marginBottom

:

 

12

 

}

}

>

                

{

paragraph

}

              

</Text

>

            

)

)

}

          

</View

>

        

</View

>

      

</Spoiler

>

    

</Card

>

  

)

;

}

Scan to open this page on your phonereact-ui-library.com/components/Spoiler

</>

react-ui-library

100+ accessible, themeable components that work seamlessly across iOS, Android, and Web.

A Platform Blocks product.