Skip to content

Qwik

Why Qwik + Alap

Qwik's defining feature is resumability — zero JavaScript executes until the user interacts. Alap already serializes query state into HTML attributes, so the engine, parser, and placement logic are only downloaded when someone actually clicks a link. Put 500 Alap menus on a page and the browser won't execute a single line of Alap's expression parser until the first hover.

Install

bash
npm install alap @builder.io/qwik

Setup

tsx
import { component$ } from '@builder.io/qwik';
import { AlapProvider, AlapLink } from 'alap/qwik';
import config from './alap-config';

export default component$(() => {
  return (
    <AlapProvider config={config}>
      <p>Check out <AlapLink query=".coffee">cafes</AlapLink>.</p>
    </AlapProvider>
  );
});

Components

Same Provider/Link/Hook pattern as the other adapters, adapted for Qwik's resumable architecture:

  • All components use component$() — Qwik's lazy-loadable component boundary
  • Event handlers use $() closures — handler code downloads on demand, not at page load
  • useVisibleTask$ for browser-only effects (dismissal, placement, focus management)
  • noSerialize wraps the AlapEngine — it only runs client-side, never serialized to HTML

<AlapProvider>

PropTypeDefaultDescription
configAlapConfigrequiredThe link configuration
menuTimeoutnumberfrom configAuto-dismiss timeout override
defaultMenuClassNamestringDefault CSS class for all menus

Children go inside the provider via Qwik's <Slot />:

tsx
<AlapProvider config={config}>
  {/* AlapLink components here */}
</AlapProvider>
PropTypeDefaultDescription
querystringrequiredExpression to evaluate
anchorIdstringAnchor ID for bare @ macro
mode'dom' | 'popover''dom'Rendering mode
classstringCSS class on trigger
menuClassNamestringCSS class on menu container
listType'ul' | 'ol'from configList element type
maxVisibleItemsnumberfrom configScroll after N items
placementPlacementCompass placement (N, NE, E, SE, S, SW, W, NW, C)
gapnumber4Pixel gap between trigger and menu
paddingnumber8Minimum distance from viewport edges
onTriggerHover$QRL<(detail) => void>Mouse enters trigger
onTriggerContext$QRL<(detail) => void>Right-click trigger
onItemHover$QRL<(detail) => void>Mouse enters menu item
onItemContext$QRL<(detail) => void>Right-click/ArrowRight on item

Trigger content goes inside via <Slot />:

tsx
<AlapLink query=".coffee">cafes</AlapLink>

useAlap()

MethodSignatureDescription
query(expression, anchorId?) => string[]Expression to item IDs
resolve(expression, anchorId?) => Array<{ id } & AlapLink>Expression to full link objects
getLinks(ids) => Array<{ id } & AlapLink>IDs to full link objects

Must be called inside an <AlapProvider>.

Event hooks

Qwik callbacks use the $ suffix convention — they're QRL (Qwik Resource Locator) functions that serialize across the lazy-loading boundary:

tsx
<AlapLink
  query=".coffee"
  onItemHover$={$((detail) => {
    console.log('Hovering:', detail.link.label);
  })}
>
  cafes
</AlapLink>

Qwik City Integration

For Qwik City projects, the qwik-alap integration auto-injects web component registration and config loading into every page:

bash
npm install qwik-alap
ts
// vite.config.ts
import { qwikCity } from '@builder.io/qwik-city/vite';
import { qwikVite } from '@builder.io/qwik/optimizer';
import { alapPlugin } from 'qwik-alap';

export default defineConfig({
  plugins: [
    qwikCity(),
    qwikVite(),
    alapPlugin({ config: './src/alap-config.ts' }),
  ],
});

Then use <alap-link> web components anywhere — no import needed:

html
<alap-link query=".coffee">cafes</alap-link>

Integration options

OptionTypeDefaultDescription
configstring'./src/alap-config.ts'Path to config file
configNamestringNamed config for multi-config setups
validatebooleantrueValidate config at build time
injectStylesbooleanfalseInject default light/dark stylesheet

Adapter vs. Integration

Adapter (alap/qwik)Integration (qwik-alap)
WhatFramework-native componentsVite plugin for Qwik City
WhenFull control, framework treeZero-config, web components
RenderingQwik components<alap-link> custom elements
SetupManual Provider + configOne line in vite.config.ts

Use the adapter when you want Qwik-native components in your component tree. Use the integration when you want automatic setup with the web component.

See also