or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

browser-apis.mdbrowser-events.mddevice-sensors.mdelement-tracking.mdindex.mdmouse-pointer.mdscroll-resize.mdtheme-preferences.mdutilities-advanced.mdwindow-document.md

browser-apis.mddocs/

0

# Browser APIs

1

2

Components for interacting with various browser APIs like clipboard, geolocation, fullscreen, and media features.

3

4

## Capabilities

5

6

### UseClipboard Component

7

8

Provides clipboard read and write functionality with reactive state.

9

10

```typescript { .api }

11

/**

12

* Component that provides clipboard read/write functionality

13

* @example

14

* <UseClipboard v-slot="{ text, copy, isSupported }">

15

* <div>

16

* <p>Clipboard: {{ text }}</p>

17

* <button @click="copy('Hello!')">Copy Text</button>

18

* </div>

19

* </UseClipboard>

20

*/

21

interface UseClipboardProps {

22

/** Text source to read from @default undefined */

23

source?: MaybeRefOrGetter<string>;

24

/** Whether to read clipboard content immediately @default false */

25

read?: boolean;

26

/** Legacy mode using document.execCommand @default false */

27

legacy?: boolean;

28

/** Copy options */

29

copiedDuring?: number;

30

}

31

32

/** Slot data exposed by UseClipboard component */

33

interface UseClipboardReturn {

34

/** Whether clipboard API is supported */

35

isSupported: Ref<boolean>;

36

/** Current clipboard text content */

37

text: Ref<string>;

38

/** Whether clipboard was recently copied */

39

copied: Ref<boolean>;

40

/** Copy text to clipboard */

41

copy: (text?: string) => Promise<void>;

42

}

43

```

44

45

**Usage Examples:**

46

47

```vue

48

<template>

49

<!-- Basic clipboard usage -->

50

<UseClipboard v-slot="{ text, copy, copied, isSupported }">

51

<div v-if="isSupported" class="clipboard-demo">

52

<h3>Clipboard Demo</h3>

53

<p>Current clipboard: {{ text || 'Empty' }}</p>

54

<div class="clipboard-actions">

55

<button @click="copy('Hello World!')" :disabled="copied">

56

{{ copied ? 'Copied!' : 'Copy Hello World' }}

57

</button>

58

<button @click="copy(customText)">

59

Copy Custom Text

60

</button>

61

</div>

62

<input v-model="customText" placeholder="Enter text to copy" />

63

</div>

64

<div v-else>Clipboard API not supported</div>

65

</UseClipboard>

66

67

<!-- Auto-read clipboard -->

68

<UseClipboard :read="true" v-slot="{ text, copy }">

69

<div class="auto-clipboard">

70

<p>Auto-synced clipboard: {{ text }}</p>

71

<button @click="copy(`Timestamp: ${Date.now()}`)">

72

Copy Timestamp

73

</button>

74

</div>

75

</UseClipboard>

76

77

<!-- Copy from source -->

78

<UseClipboard :source="sourceText" v-slot="{ copy, copied }">

79

<button @click="copy()" :class="{ copied }">

80

{{ copied ? 'Copied!' : 'Copy Source Text' }}

81

</button>

82

</UseClipboard>

83

</template>

84

85

<script setup>

86

import { ref } from 'vue';

87

import { UseClipboard } from '@vueuse/components';

88

89

const customText = ref('');

90

const sourceText = ref('This is source text to copy');

91

</script>

92

93

<style>

94

.clipboard-actions {

95

margin: 10px 0;

96

}

97

98

.clipboard-actions button {

99

margin-right: 10px;

100

padding: 8px 16px;

101

}

102

103

.copied {

104

background-color: #4caf50;

105

color: white;

106

}

107

</style>

108

```

109

110

### UseGeolocation Component

111

112

Provides geolocation data from the browser's Geolocation API.

113

114

```typescript { .api }

115

/**

116

* Component that provides geolocation data

117

* @example

118

* <UseGeolocation v-slot="{ coords, error, resume, pause }">

119

* <div>Location: {{ coords.latitude }}, {{ coords.longitude }}</div>

120

* </UseGeolocation>

121

*/

122

interface UseGeolocationProps {

123

/** High accuracy mode @default true */

124

enableHighAccuracy?: boolean;

125

/** Maximum age of cached position (ms) @default 30000 */

126

maximumAge?: number;

127

/** Timeout for position request (ms) @default 27000 */

128

timeout?: number;

129

/** Start watching immediately @default true */

130

immediate?: boolean;

131

}

132

133

/** Slot data exposed by UseGeolocation component */

134

interface UseGeolocationReturn {

135

/** Whether geolocation is supported */

136

isSupported: Ref<boolean>;

137

/** Current position coordinates */

138

coords: Ref<GeolocationCoordinates>;

139

/** Location timestamp */

140

locatedAt: Ref<number | null>;

141

/** Geolocation error */

142

error: Ref<GeolocationPositionError | null>;

143

/** Start/resume location tracking */

144

resume: () => void;

145

/** Pause location tracking */

146

pause: () => void;

147

}

148

149

interface GeolocationCoordinates {

150

/** Latitude in decimal degrees */

151

latitude: number;

152

/** Longitude in decimal degrees */

153

longitude: number;

154

/** Altitude in meters above sea level */

155

altitude: number | null;

156

/** Accuracy of lat/lng in meters */

157

accuracy: number;

158

/** Accuracy of altitude in meters */

159

altitudeAccuracy: number | null;

160

/** Direction of travel in degrees */

161

heading: number | null;

162

/** Speed in meters per second */

163

speed: number | null;

164

}

165

166

interface GeolocationPositionError {

167

code: number;

168

message: string;

169

}

170

```

171

172

**Usage Examples:**

173

174

```vue

175

<template>

176

<!-- Basic geolocation -->

177

<UseGeolocation v-slot="{ coords, error, isSupported, locatedAt }">

178

<div v-if="isSupported" class="geolocation-info">

179

<h3>Your Location</h3>

180

<div v-if="error" class="error">

181

Error: {{ error.message }}

182

</div>

183

<div v-else-if="coords.latitude">

184

<p>πŸ“ {{ coords.latitude.toFixed(6) }}, {{ coords.longitude.toFixed(6) }}</p>

185

<p>πŸ“ Accuracy: Β±{{ Math.round(coords.accuracy) }}m</p>

186

<p v-if="coords.altitude">πŸ”οΈ Altitude: {{ Math.round(coords.altitude) }}m</p>

187

<p v-if="coords.speed">πŸƒ Speed: {{ (coords.speed * 3.6).toFixed(1) }} km/h</p>

188

<p v-if="coords.heading">🧭 Heading: {{ Math.round(coords.heading) }}°</p>

189

<p>⏰ Updated: {{ new Date(locatedAt).toLocaleTimeString() }}</p>

190

</div>

191

<div v-else class="loading">

192

πŸ“‘ Getting your location...

193

</div>

194

</div>

195

<div v-else>Geolocation not supported</div>

196

</UseGeolocation>

197

198

<!-- Controlled geolocation -->

199

<UseGeolocation

200

:immediate="false"

201

:enable-high-accuracy="false"

202

v-slot="{ coords, resume, pause, error }"

203

>

204

<div class="controlled-geo">

205

<div class="geo-controls">

206

<button @click="resume">Start Tracking</button>

207

<button @click="pause">Stop Tracking</button>

208

</div>

209

<div v-if="coords.latitude" class="coordinates">

210

Low accuracy location: {{ coords.latitude.toFixed(4) }}, {{ coords.longitude.toFixed(4) }}

211

</div>

212

<div v-if="error" class="error">{{ error.message }}</div>

213

</div>

214

</UseGeolocation>

215

</template>

216

217

<script setup>

218

import { UseGeolocation } from '@vueuse/components';

219

</script>

220

221

<style>

222

.error {

223

color: #f44336;

224

padding: 10px;

225

background: #ffebee;

226

border-radius: 4px;

227

}

228

229

.loading {

230

color: #2196f3;

231

font-style: italic;

232

}

233

234

.geo-controls button {

235

margin-right: 10px;

236

padding: 8px 16px;

237

}

238

</style>

239

```

240

241

### UseFullscreen Component

242

243

Manages fullscreen mode for elements with the Fullscreen API.

244

245

```typescript { .api }

246

/**

247

* Component that manages fullscreen mode

248

* @example

249

* <UseFullscreen v-slot="{ isFullscreen, enter, exit, toggle }">

250

* <div>

251

* <button @click="toggle">{{ isFullscreen ? 'Exit' : 'Enter' }} Fullscreen</button>

252

* </div>

253

* </UseFullscreen>

254

*/

255

interface UseFullscreenProps extends RenderableComponent {

256

/** Auto-exit fullscreen when component unmounts @default false */

257

autoExit?: boolean;

258

}

259

260

/** Slot data exposed by UseFullscreen component */

261

interface UseFullscreenReturn {

262

/** Whether fullscreen API is supported */

263

isSupported: Ref<boolean>;

264

/** Whether element is in fullscreen */

265

isFullscreen: Ref<boolean>;

266

/** Enter fullscreen mode */

267

enter: () => Promise<void>;

268

/** Exit fullscreen mode */

269

exit: () => Promise<void>;

270

/** Toggle fullscreen mode */

271

toggle: () => Promise<void>;

272

}

273

```

274

275

**Usage Examples:**

276

277

```vue

278

<template>

279

<!-- Basic fullscreen -->

280

<UseFullscreen v-slot="{ isFullscreen, toggle, isSupported }">

281

<div v-if="isSupported" class="fullscreen-demo">

282

<div class="content" :class="{ 'fullscreen-content': isFullscreen }">

283

<h3>{{ isFullscreen ? '🎯 Fullscreen Mode!' : 'πŸ“± Normal Mode' }}</h3>

284

<p>This content can go fullscreen</p>

285

<button @click="toggle" class="fullscreen-btn">

286

{{ isFullscreen ? 'Exit Fullscreen' : 'Go Fullscreen' }}

287

</button>

288

</div>

289

</div>

290

<div v-else>Fullscreen API not supported</div>

291

</UseFullscreen>

292

293

<!-- Video fullscreen -->

294

<UseFullscreen v-slot="{ isFullscreen, enter, exit }">

295

<div class="video-container">

296

<video

297

ref="videoRef"

298

controls

299

width="400"

300

:style="{ width: isFullscreen ? '100vw' : '400px' }"

301

>

302

<source src="/sample-video.mp4" type="video/mp4">

303

</video>

304

<div class="video-controls">

305

<button @click="enter">πŸ“Ί Fullscreen Video</button>

306

<button @click="exit" :disabled="!isFullscreen">↩️ Exit</button>

307

</div>

308

</div>

309

</UseFullscreen>

310

311

<!-- Auto-exit fullscreen -->

312

<UseFullscreen :auto-exit="true" v-slot="{ isFullscreen, toggle }">

313

<div class="auto-exit-demo">

314

<p>Auto-exits fullscreen when component unmounts</p>

315

<button @click="toggle">Toggle Fullscreen</button>

316

<p>Status: {{ isFullscreen ? 'Fullscreen' : 'Windowed' }}</p>

317

</div>

318

</UseFullscreen>

319

</template>

320

321

<script setup>

322

import { ref } from 'vue';

323

import { UseFullscreen } from '@vueuse/components';

324

325

const videoRef = ref();

326

</script>

327

328

<style>

329

.fullscreen-demo {

330

border: 2px solid #ccc;

331

border-radius: 8px;

332

overflow: hidden;

333

}

334

335

.content {

336

padding: 20px;

337

background: #f9f9f9;

338

min-height: 200px;

339

display: flex;

340

flex-direction: column;

341

align-items: center;

342

justify-content: center;

343

}

344

345

.fullscreen-content {

346

background: #1976d2;

347

color: white;

348

min-height: 100vh;

349

}

350

351

.fullscreen-btn {

352

padding: 12px 24px;

353

font-size: 16px;

354

border: none;

355

border-radius: 6px;

356

background: #2196f3;

357

color: white;

358

cursor: pointer;

359

}

360

361

.video-controls {

362

padding: 10px;

363

display: flex;

364

gap: 10px;

365

}

366

</style>

367

```

368

369

### UseEyeDropper Component

370

371

Provides color picking functionality using the EyeDropper API.

372

373

```typescript { .api }

374

/**

375

* Component that provides color picker functionality

376

* @example

377

* <UseEyeDropper v-slot="{ isSupported, sRGBHex, open }">

378

* <div>

379

* <button @click="open">Pick Color</button>

380

* <div>Color: {{ sRGBHex }}</div>

381

* </div>

382

* </UseEyeDropper>

383

*/

384

interface UseEyeDropperProps {

385

// No props - uses browser EyeDropper API directly

386

}

387

388

/** Slot data exposed by UseEyeDropper component */

389

interface UseEyeDropperReturn {

390

/** Whether EyeDropper API is supported */

391

isSupported: Ref<boolean>;

392

/** Selected color in sRGB hex format */

393

sRGBHex: Ref<string>;

394

/** Open color picker */

395

open: (options?: EyeDropperOpenOptions) => Promise<void>;

396

}

397

398

interface EyeDropperOpenOptions {

399

signal?: AbortSignal;

400

}

401

```

402

403

**Usage Examples:**

404

405

```vue

406

<template>

407

<!-- Basic color picker -->

408

<UseEyeDropper v-slot="{ isSupported, sRGBHex, open }">

409

<div v-if="isSupported" class="color-picker">

410

<h3>Color Picker</h3>

411

<div class="color-display">

412

<div

413

class="color-swatch"

414

:style="{ backgroundColor: sRGBHex || '#transparent' }"

415

></div>

416

<span class="color-value">{{ sRGBHex || 'No color selected' }}</span>

417

</div>

418

<button @click="open" class="pick-button">

419

🎨 Pick Color from Screen

420

</button>

421

</div>

422

<div v-else>EyeDropper API not supported</div>

423

</UseEyeDropper>

424

425

<!-- Color palette builder -->

426

<UseEyeDropper v-slot="{ isSupported, sRGBHex, open }">

427

<div v-if="isSupported" class="palette-builder">

428

<h3>Build Color Palette</h3>

429

<div class="palette">

430

<div

431

v-for="(color, index) in palette"

432

:key="index"

433

class="palette-color"

434

:style="{ backgroundColor: color }"

435

:title="color"

436

></div>

437

</div>

438

<div class="palette-actions">

439

<button @click="addColor" :disabled="!sRGBHex">

440

Add Current Color

441

</button>

442

<button @click="open">Pick New Color</button>

443

<button @click="clearPalette">Clear Palette</button>

444

</div>

445

<p>Current: {{ sRGBHex || 'Pick a color' }}</p>

446

</div>

447

</UseEyeDropper>

448

</template>

449

450

<script setup>

451

import { ref, watch } from 'vue';

452

import { UseEyeDropper } from '@vueuse/components';

453

454

const palette = ref([]);

455

456

const addColor = () => {

457

// This would need access to sRGBHex from the slot

458

// In practice, you'd use a composable or different pattern

459

};

460

461

const clearPalette = () => {

462

palette.value = [];

463

};

464

</script>

465

466

<style>

467

.color-display {

468

display: flex;

469

align-items: center;

470

gap: 10px;

471

margin: 15px 0;

472

}

473

474

.color-swatch {

475

width: 50px;

476

height: 50px;

477

border: 2px solid #ccc;

478

border-radius: 6px;

479

box-shadow: inset 0 0 10px rgba(0,0,0,0.1);

480

}

481

482

.pick-button {

483

padding: 10px 20px;

484

background: #ff5722;

485

color: white;

486

border: none;

487

border-radius: 6px;

488

cursor: pointer;

489

font-size: 16px;

490

}

491

492

.palette {

493

display: flex;

494

flex-wrap: wrap;

495

gap: 5px;

496

margin: 15px 0;

497

min-height: 60px;

498

border: 2px dashed #ccc;

499

border-radius: 6px;

500

padding: 10px;

501

}

502

503

.palette-color {

504

width: 40px;

505

height: 40px;

506

border-radius: 4px;

507

border: 1px solid #ddd;

508

}

509

510

.palette-actions {

511

display: flex;

512

gap: 10px;

513

}

514

515

.palette-actions button {

516

padding: 8px 16px;

517

border: 1px solid #ccc;

518

border-radius: 4px;

519

cursor: pointer;

520

}

521

</style>

522

```

523

524

### UseBrowserLocation Component

525

526

Tracks browser location and URL information.

527

528

```typescript { .api }

529

/**

530

* Component that tracks browser location/URL information

531

* @example

532

* <UseBrowserLocation v-slot="{ url, origin, pathname, search }">

533

* <div>Current path: {{ pathname }}{{ search }}</div>

534

* </UseBrowserLocation>

535

*/

536

interface UseBrowserLocationProps {

537

// No props - uses browser location API directly

538

}

539

540

/** Slot data exposed by UseBrowserLocation component */

541

interface BrowserLocationState {

542

/** Reactive trigger ref for updates */

543

trigger: Ref<string>;

544

/** Complete URL */

545

url: ComputedRef<string>;

546

/** URL origin */

547

origin: ComputedRef<string>;

548

/** URL protocol */

549

protocol: ComputedRef<string>;

550

/** URL host */

551

host: ComputedRef<string>;

552

/** URL hostname */

553

hostname: ComputedRef<string>;

554

/** URL port */

555

port: ComputedRef<string>;

556

/** URL pathname */

557

pathname: ComputedRef<string>;

558

/** URL search params */

559

search: ComputedRef<string>;

560

/** URL hash */

561

hash: ComputedRef<string>;

562

}

563

```

564

565

**Usage Examples:**

566

567

```vue

568

<template>

569

<!-- Basic location info -->

570

<UseBrowserLocation v-slot="{ url, pathname, search, hash, origin }">

571

<div class="location-info">

572

<h3>Browser Location</h3>

573

<div class="url-parts">

574

<p><strong>Full URL:</strong> {{ url }}</p>

575

<p><strong>Origin:</strong> {{ origin }}</p>

576

<p><strong>Path:</strong> {{ pathname }}</p>

577

<p><strong>Search:</strong> {{ search || '(none)' }}</p>

578

<p><strong>Hash:</strong> {{ hash || '(none)' }}</p>

579

</div>

580

</div>

581

</UseBrowserLocation>

582

583

<!-- URL analyzer -->

584

<UseBrowserLocation v-slot="{ protocol, host, port, pathname, search }">

585

<div class="url-analyzer">

586

<h3>URL Analysis</h3>

587

<table class="url-table">

588

<tr><td>Protocol:</td><td>{{ protocol }}</td></tr>

589

<tr><td>Host:</td><td>{{ host }}</td></tr>

590

<tr><td>Port:</td><td>{{ port || '(default)' }}</td></tr>

591

<tr><td>Path:</td><td>{{ pathname }}</td></tr>

592

<tr><td>Query:</td><td>{{ search || '(none)' }}</td></tr>

593

</table>

594

</div>

595

</UseBrowserLocation>

596

</template>

597

598

<script setup>

599

import { UseBrowserLocation } from '@vueuse/components';

600

</script>

601

602

<style>

603

.location-info, .url-analyzer {

604

border: 1px solid #ddd;

605

border-radius: 6px;

606

padding: 15px;

607

margin: 15px 0;

608

}

609

610

.url-table {

611

width: 100%;

612

border-collapse: collapse;

613

}

614

615

.url-table td {

616

padding: 8px;

617

border-bottom: 1px solid #eee;

618

}

619

620

.url-table td:first-child {

621

font-weight: bold;

622

width: 100px;

623

}

624

</style>

625

```

626

627

## Type Definitions

628

629

```typescript { .api }

630

/** Common types used across browser API components */

631

type MaybeRefOrGetter<T> = T | Ref<T> | (() => T);

632

633

interface RenderableComponent {

634

/** The element that the component should be rendered as @default 'div' */

635

as?: object | string;

636

}

637

638

/** Clipboard API types */

639

interface ClipboardItem {

640

readonly types: string[];

641

getType(type: string): Promise<Blob>;

642

}

643

644

/** Geolocation API types */

645

interface GeolocationPosition {

646

coords: GeolocationCoordinates;

647

timestamp: number;

648

}

649

650

interface GeolocationPositionError {

651

readonly code: number;

652

readonly message: string;

653

readonly PERMISSION_DENIED: number;

654

readonly POSITION_UNAVAILABLE: number;

655

readonly TIMEOUT: number;

656

}

657

658

/** Fullscreen API types */

659

interface FullscreenOptions {

660

navigationUI?: 'auto' | 'show' | 'hide';

661

}

662

663

/** EyeDropper API types */

664

interface EyeDropper {

665

open(options?: EyeDropperOpenOptions): Promise<ColorSelectionResult>;

666

}

667

668

interface ColorSelectionResult {

669

sRGBHex: string;

670

}

671

```