Spoiler

Hides spoilers until they are revealed by a click or hover.

Volume three ends with , so read it after the main text.

<script setup lang="ts">
  import { Spoiler, Text } from '@hina-ui/vue'
</script>

<template>
  <Text class="max-w-lg">
    Volume three ends with
    <Spoiler>the two deciding to travel on together</Spoiler>
    , so read it after the main text.
  </Text>
</template>
vue

Usage

import { Spoiler } from '@hina-ui/vue'
ts

Put the text to hide in the default slot. While hidden it is covered in noise and cannot be selected; a click reveals it, expanding outward from where the pointer landed.

Click to reveal , and click again to hide it.

<script setup lang="ts">
  import { Spoiler, Text } from '@hina-ui/vue'
</script>

<template>
  <Text class="max-w-lg">
    Click to reveal
    <Spoiler>this hidden line</Spoiler>
    , and click again to hide it.
  </Text>
</template>
vue

Examples

Revealing on hover

With reveal-on="hover" the content is revealed as the pointer enters and hidden again as it leaves. Keyboard focus and blur do the same.

Move the pointer in to see , and it hides again as the pointer leaves.

<script setup lang="ts">
  import { Spoiler, Text } from '@hina-ui/vue'
</script>

<template>
  <Text class="max-w-lg">
    Move the pointer in to see
    <Spoiler reveal-on="hover">the hidden content</Spoiler>
    , and it hides again as the pointer leaves.
  </Text>
</template>
vue

Controlled

hidden supports two-way binding, so a whole passage can be revealed from outside.

How it ends:

<script setup lang="ts">
  import { ref } from 'vue'
  import { Button, Spoiler, Stack, Text } from '@hina-ui/vue'

  const hidden = ref(true)
</script>

<template>
  <Stack class="max-w-lg">
    <Text>
      How it ends:
      <Spoiler v-model:hidden="hidden">the deal turns over at the last moment</Spoiler>
    </Text>
    <Button variant="outline" tone="neutral" size="sm" @click="hidden = !hidden">
      {{ hidden ? 'Reveal all' : 'Hide all' }}
    </Button>
  </Stack>
</template>
vue

Content across several lines

A passage spanning several lines can be hidden as a whole. The reveal is centred on the pointer and spreads line by line.

<script setup lang="ts">
  import { Spoiler, Text } from '@hina-ui/vue'
</script>

<template>
  <Text class="max-w-sm">
    <Spoiler>
      A spoiler spanning several lines can be hidden as a whole; revealing it starts where the
      pointer lands and fills the passage line by line.
    </Spoiler>
  </Text>
</template>
vue

Fallback

The noise cover relies on the browser’s paint worklet. Without it the component falls back to a tinted background with a blur, behaving exactly the same. Set force-fallback to use that form deliberately.

Default form:

Fallback form:

<script setup lang="ts">
  import { Spoiler, Stack, Text } from '@hina-ui/vue'
</script>

<template>
  <Stack class="max-w-lg">
    <Text>
      Default form:
      <Spoiler>noise cover</Spoiler>
    </Text>
    <Text>
      Fallback form:
      <Spoiler force-fallback>tint and blur</Spoiler>
    </Text>
  </Stack>
</template>
vue

Behaviour

  • Hidden text cannot be selected or copied.
  • A reveal expands from the pointer, or from the geometric centre when triggered by keyboard.

Accessibility

  • In click mode the component renders with role="button", takes focus, and responds to both Enter and Space.
  • The accessible name changes with state, reading as a prompt to reveal while hidden and as a prompt to hide once revealed.
  • aria-expanded reflects whether the content is revealed.

API

Props

Prop
Type
Default
Description
hidden
boolean
true
Whether hidden; supports v-model
revealOn
'click' | 'hover'
'click'
How it is revealed
forceFallback
boolean
false
Force the fallback form
class
string
—
Classes appended to the root

Slots

Slot
Description
default
The hidden content