Display

Visually Hidden

Content that stays out of view but is still announced by assistive technology — a typed wrapper around juxt.ui’s shared sr-only utility.

Copy
<script setup lang="ts">
import { Search } from '@lucide/vue'
</script>

<template>
  <button type="button" class="j-focusable grid h-9 w-9 place-items-center rounded-md border border-border text-fg-muted transition-colors hover:bg-surface-hover hover:text-fg">
    <Search class="h-4 w-4" />
    <JVisuallyHidden>Search</JVisuallyHidden>
  </button>
</template>

Installation #

With the Nuxt module, every component is auto-imported — there is nothing to add. In a plain Vue project, import what you use:

Copy
import { JVisuallyHidden } from '@juxtui/ui'

Usage #

Copy
<button type="button">
  <SearchIcon />
  <JVisuallyHidden>Search</JVisuallyHidden>
</button>

Always hidden — unlike a "skip link" pattern, it never reappears on focus. For a link that should become visible on keyboard focus, build that separately.

Renders as a <span> by default; use as to render a <label>, a heading or anything else that needs its own semantics while staying visually hidden.

Variants & examples #

As a form label#

Pair a visually hidden <label> with a placeholder-only input, so the field still has a real accessible name.

Copy
<script setup lang="ts">
const query = ref('')
</script>

<template>
  <div class="flex w-full max-w-xs items-center gap-2 rounded-md border border-border px-3 py-2">
    <JVisuallyHidden as="label" for="site-search">
      Search the site
    </JVisuallyHidden>
    <input id="site-search" v-model="query" type="search" placeholder="Search…" class="w-full bg-transparent text-sm text-fg outline-none placeholder:text-fg-muted">
  </div>
</template>

As a hidden heading#

Gives a landmark region a real heading for screen readers while the sighted design shows only a logo mark.

Company logo

J
juxt.ui
Copy
<template>
  <section aria-labelledby="brand-heading" class="flex items-center gap-3 rounded-lg border border-border p-4">
    <JVisuallyHidden id="brand-heading" as="h2">
      Company logo
    </JVisuallyHidden>
    <div class="grid h-8 w-8 place-items-center rounded-md bg-ink text-xs font-semibold text-ink-fg">
      J
    </div>
    <span class="text-sm text-fg-muted">juxt.ui</span>
  </section>
</template>

API #

Props

PropTypeDefault Description
asstring | Component'span'Render as another element or component, e.g. label or h2.

Slots

SlotProps Description
default—The hidden content.

Accessibility #

  • Uses the same clip-based hiding technique as most design systems: present in the accessibility tree and readable by screen readers, but removed from visual layout and pointer interaction.
  • Does not affect focusability — if the wrapped content is interactive (e.g. a link), it stays in the tab order.