Skip to content
omaris

Foundations

Magnifier

A loupe that really magnifies: live text scaled by the browser, so it is crisp at 4x rather than four times as blurry.

import { Magnifier } from 'omaris'
Learn

Examples

Basic

Move the pointer over the fine print — or, on a touch screen, press and hold it. The glass holds a live copy of the text scaled by the browser, so the letters are as sharp at 2.4× as they are at 1×.

Clause 7.2 — The subscriber grants the operator a non-exclusive licence to cache, transcode and redistribute the submitted material for the sole purpose of delivery, for the term of the agreement and for ninety days thereafter, in any territory in which the operator maintains a point of presence.

<script lang="ts">	import { Magnifier, Text } from 'omaris';</script>​<div class="w-full max-w-md rounded-shape-lg border border-border p-4">	<Magnifier zoom={2.4}>		<Text variant="body-sm" tone="muted">			Clause 7.2 — The subscriber grants the operator a non-exclusive licence to cache, transcode			and redistribute the submitted material for the sole purpose of delivery, for the term of the			agreement and for ninety days thereafter, in any territory in which the operator maintains a			point of presence.		</Text>	</Magnifier></div>

Picture

The other half of the job: a picture at 3×. Hover it, or press and hold on a phone. Vector art stays vector inside the lens, and pixelated is there for when enlarged pixels are the point.

Erbil citadel
<script lang="ts">	import { Magnifier } from 'omaris';</script>​<div class="w-full max-w-sm">	<Magnifier src="/docs/photos/erbil.svg" alt="Erbil citadel" zoom={3} width={160} /></div>

Text loupe

The system loupe, as a component: press and hold, and a wide rounded glass comes up above the finger and follows it. trigger="press" asks for that behaviour on a mouse as well, which is how you can try it here.

Press and hold anywhere in this paragraph. The glass rides above the pointer rather than under it, so nothing you are trying to read is covered by the thing reading it — and it is real text under there, not an enlarged screenshot.

<script lang="ts">	import { Magnifier, Text } from 'omaris';</script>​<div class="w-full max-w-md rounded-shape-lg bg-surface-container-low p-4">	<Magnifier shape="rounded" zoom={1.9} width={220} height={72} trigger="press" hold={220}>		<Text variant="body-md">			Press and hold anywhere in this paragraph. The glass rides above the pointer rather than under			it, so nothing you are trying to read is covered by the thing reading it — and it is real text			under there, not an enlarged screenshot.		</Text>	</Magnifier></div>

Fluid

fluid turns the disc into a drop of glass: it eases after the pointer, stretches along its own motion and rounds out as it slows, and the picture bends at the rim with a fine colour fringe — the way a real loupe does. Sweep the pointer across quickly and watch it lag and lengthen.

Clause 7.2 — The subscriber grants the operator a non-exclusive licence to cache, transcode and redistribute the submitted material for the sole purpose of delivery, for the term of the agreement and for ninety days thereafter, in any territory in which the operator maintains a point of presence.

<script lang="ts">	import { Magnifier, Text } from 'omaris';</script>​<div class="w-full max-w-md rounded-shape-lg border border-border p-4">	<Magnifier zoom={2.4} fluid width={150}>		<Text variant="body-sm" tone="muted">			Clause 7.2 — The subscriber grants the operator a non-exclusive licence to cache, transcode			and redistribute the submitted material for the sole purpose of delivery, for the term of the			agreement and for ninety days thereafter, in any territory in which the operator maintains a			point of presence.		</Text>	</Magnifier></div>

Overridden

The overridden case: a square glass sized from classes, its rim and sheen replaced, and pixelated so the enlargement shows the grid rather than smoothing it away.

<script lang="ts">	import { Magnifier } from 'omaris';</script>​<div class="w-full max-w-md">	<Magnifier		zoom={4}		shape="square"		pixelated		width="14rem"		height="7rem"		classes={{			lens: 'rounded-shape-sm ring-2 ring-primary shadow-3',			sheen: 'bg-none ring-inset ring-primary/30'		}}	>		<div class="grid grid-cols-8 gap-px rounded-shape-sm bg-border p-px">			{#each Array.from({ length: 32 }, (_, i) => i) as cell (cell)}				<div					class="aspect-square"					class:bg-primary={cell % 3 === 0}					class:bg-surface-container-high={cell % 3 !== 0}				></div>			{/each}		</div>	</Magnifier></div>

When to use it

Use it for

  • Fine print people must be able to read: terms, a receipt, a footnote, a table at 11px. The lens holds live text scaled by the browser, so it is legible rather than blurry.
  • A picture with detail that matters: a site plan, a scan, a product close-up, a map tile. src takes the picture directly.
  • A dense diagram or chart where the labels are smaller than the shapes.
  • A sprite sheet, a QR code or anything whose pixels are the subject. pixelated enlarges them instead of smoothing them.
  • The system loupe, for a phone user picking a point precisely: trigger="press" with a wide shape="rounded" glass above the finger.

Not for

  • Looking at a photograph properly, with panning, pinching and full-screen → Image Viewer.
  • Cropping or choosing a region of an image → Image Cropper.
  • More detail about a thing rather than a bigger copy of it → Tooltip or Popover.
  • Reading a whole document larger → let the browser zoom, or offer a type-size control. A loupe is for a spot, not a page.
  • Live content: a video, a canvas, an animating chart. The copy is taken when the lens opens; live re-takes it on DOM changes, but a <canvas> or a playing <video> does not come with it.

Do

  • Keep zoom between 2 and 3 for text. Past about 4 the lens shows three words and the reader loses their place.
  • Use lift (or leave it 'auto') on touch, so the glass is not under the finger.
  • Give the content a real width. The copy is laid out at the source's own width, so a w-full source in a narrow column magnifies what is on screen.
  • Leave keyboard on. The control is invisible until focused, and it is the only way a keyboard user gets the same help.
  • Use shape="rounded" with a wide width for text and a circle for pictures.

Don't

  • Wrap an interactive region and expect the copy to be interactive. It is inert: nothing inside the lens is focusable and no handler fires twice.
  • Turn live on for a page that mutates constantly. It re-copies the subtree on every change.
  • Put one inside a scrolling column without trigger="press". A hover lens on a touch screen fires on the first tap of a scroll.
  • Magnify something that could simply be bigger. The lens is for content that has to stay small.

Quick reference

shape
  • circle (default)
  • rounded
  • square

API

Magnifier

A loupe that really magnifies — text included.

Wrap anything. A pointer over it (or a press and hold on a touch screen) raises a lens that follows the finger and shows what is under it, larger.

It is not a zoomed screenshot. The lens holds a live copy of the content, scaled with a CSS transform, so the browser lays the text out and rasterises it at the magnified size: glyphs are as crisp at 4× as they are at 1×, and vector art, borders and shadows come with them. A background-image trick can only ever enlarge pixels, which is why the usual "product zoom" turns type to mush.

The copy is taken when the lens opens and is inert — no ids collide, no handler fires twice, nothing inside it is focusable. Content that changes while the lens is up wants live, which re-takes it as the DOM changes.

On a touch screen it behaves like the system loupe: press and hold for hold ms to summon it, then drag. The glass rides above the finger and — the part that is usually got wrong — it looks where it sits, not at what the finger is covering. Aiming a loupe at the one spot you cannot see is guesswork; here the thing under the glass is the thing you are inspecting, and the finger stays out of the picture. A finger that travels before the hold is up was scrolling, and is left alone — so the page still scrolls normally over a magnified region. On a mouse the lens sits on the pointer and the system cursor gets out of its way.

Keyboard users get it too — a control that appears on focus opens the lens, the arrow keys walk it around, and Escape puts it away.

`fluid` makes it a drop of glass. The lens eases after the pointer instead of sitting on it, stretches a little along its own motion and rounds out again as it slows, and the picture bends at the rim — a radial displacement, with the red and blue bent by slightly different amounts so a fine colour fringe rides the edge, the way it does on a real loupe. The refraction is an SVG filter on the glass alone, not on the copy, so it costs a lens-sized area per frame whatever is under it.

import { Magnifier } from 'omaris'
<Magnifier zoom={2.5}>  <p class="text-body-sm">Terms nobody can read at this size…</p></Magnifier>​<Magnifier src="/map.png" alt="Site plan" shape="circle" zoom={3} />

Parts

Every element this renders is reachable from outside. Pass Tailwind for one part as classes={{ part: '…' }}; class covers the root and is merged last, so it always wins.

root
The frame around the content. Position lives here, and so does the long press: touch-pan-y leaves the page scrolling until the lens is actually up, and the callout suppression stops the OS offering to select the text under a finger that is trying to magnify it.
source
The content, exactly as it would have rendered without the lens.
image
A picture passed as src, for the common case.
lens
The glass. Round by default, clipped, elevated, with a rim that reads as a bevel rather than a border.
glass
The pane between the picture and the rim. The refraction filter goes here, clipped to the glass, so the sheen and the bevel above it stay sharp and the shadow outside it is not bent.
stage
The scaled copy. Everything that makes the magnification happen.
sheen
The body of the glass. A curved piece of glass is darker at its rim than at its middle — that vignette, more than any highlight, is what stops a lens reading as a circular crop. On top of it a soft glare falls from the top-left and a fainter one bounces back off the bottom edge, both blurred, because a hard-edged highlight reads as a sticker stuck to the screen.
rim
The bevel, over the glare so the edge stays crisp: a bright hairline just inside the rim, a darker one a few pixels further in, and a hairline on the rim itself.
control
The keyboard affordance — invisible until it is focused.

Props

zoom

Defaults to 2

number

How much bigger. 2 is a reading aid, 4 inspects a detail.

shape

Defaults to 'circle'

MagnifierShape

The glass's outline.

circle
rounded
square
width

Defaults to 132

number | string

Lens width — a number is px, a string is any CSS length.

height
number | string

Lens height. Defaults to width, which is what makes a circle round.

trigger

Defaults to 'auto'

MagnifierTrigger

What summons it. auto — the default — reads the pointer: a mouse opens it on hover, a finger on a press and hold.

hold

Defaults to 320

number

How long a touch has to hold still before the lens appears, in ms.

lift

Defaults to 'auto'

number | 'auto'

How far above the pointer the lens both sits and looks, in px, so a finger never covers what it is magnifying. 'auto' lifts it for touch only, by enough to clear the glass.

hideCursor

Defaults to true

boolean

Hide the system cursor while the lens is up, so nothing is drawn over the magnified content. false keeps the arrow.

open bindable

Defaults to false

boolean

Whether the lens is up. Bindable, so it can be driven from outside.

disabled

Defaults to false

boolean

Turn it off without unwrapping the content.

live

Defaults to false

boolean

Re-copy the content as it changes, for something that moves under the glass.

pixelated

Defaults to false

boolean

Enlarge the pixels rather than smoothing them.

fluid

Defaults to false

boolean

A drop of glass rather than a disc: the lens eases after the pointer, stretches along its motion, and refracts at the rim.

refraction

Defaults to 26

number

How hard the rim bends the picture with fluid, in px.

keyboard

Defaults to true

boolean

Offer the lens to the keyboard as well.

label

Defaults to 'Magnify'

string

The name of the keyboard control, and the lens's accessible label.

src
string

A picture to magnify, for the common case. Children work too.

alt
string
class
string
classes
MagnifierClasses

Per-part Tailwind overrides. class still covers the root.

children
Snippet