Framework recipes

Skynet UI is plain CSS + a behavior script — there is nothing to "integrate". These recipes cover the three things frameworks care about: loading the two files, re-initializing widgets after client-side renders, and SSR.

The universal rules
  1. Load skynet-ui.css globally; load skynet-ui.js client-side only (it touches document on load).
  2. Most behaviors are event-delegated and work on any markup whenever it appears. Only the built widgets (multiselect, OTP, sortable, split, calendar, taginput and friends) need skScan(rootElement) after you render them client-side.
  3. Overlays with ids (modals, drawers, cmdk) should live once near the document root, not inside a list you re-render.

React / Next.js

// app/layout.tsx (Next.js App Router)
import "skynet-ui/css";                      // or a <link> tag to the CDN

// app/skynet.tsx — load behaviors client-side
"use client";
import { useEffect } from "react";
export default function Skynet() {
  useEffect(() => { import("skynet-ui"); }, []);
  return null;
}

Use className as usual: <button className="sk-btn sk-btn-primary">. After rendering a built widget dynamically, call window.skScan(ref.current) in an effect. For toasts anywhere: window.skToast("Saved", "success").

Vue / Nuxt

// main.js (Vite + Vue)
import "skynet-ui/css";
import "skynet-ui";          // browser bundle — fine in a pure SPA

// Nuxt: make it a client-only plugin — plugins/skynet.client.js
import "skynet-ui/css";
import "skynet-ui";

In components, onMounted(() => window.skScan?.($el)) after inserting built widgets. data-sk-* attributes pass straight through Vue templates.

Svelte / SvelteKit

// +layout.svelte
<script>
  import "skynet-ui/css";
  import { onMount } from "svelte";
  onMount(() => import("skynet-ui"));   // client-only
</script>
<slot />

Svelte's class: directives and Skynet's state classes coexist: <div class="sk-modal" class:sk-open={showModal}> works, or use skOpenModal("id") and let the framework own only the content.

HTMX / server-rendered apps

<link rel="stylesheet" href="https://skynetui.com/skynet-ui.css">
<script src="https://skynetui.com/skynet-ui.js" defer></script>

<!-- re-init built widgets inside swapped fragments -->
<script>
  document.body.addEventListener("htmx:afterSwap", function (e) {
    window.skScan(e.detail.target);
  });
</script>

This is Skynet UI's home turf — server HTML with declarative behaviors. Delegated behaviors (modals, dropdowns, tabs, sort, filter…) work in swapped content with no extra code; the one listener above covers the built widgets. Add data-sk-transition on <html> for smooth full-page navigations.

Astro

---
// src/layouts/Base.astro
import "skynet-ui/css";
---
<html lang="en" data-sk-transition>
  <body>
    <slot />
    <script>import "skynet-ui";</script>  <!-- Astro scripts run client-side -->
  </body>
</html>

Astro pages are mostly static HTML — exactly what the framework was designed for. Inside framework islands, follow that framework's recipe above.

Web components (experimental)

<script src="https://skynetui.com/skynet-elements.js" defer></script>

<sk-icon name="check"></sk-icon>
<sk-modal id="settings" heading="Settings">
  <p>Any content</p>
</sk-modal>
<button data-sk-open="settings" class="sk-btn">Open</button>

skynet-elements.js wraps the standard markup in custom elements for JSX/template ergonomics. Light DOM — themes and utilities apply normally. API: el.open(), el.close(), the open attribute, plus everything data-sk-open/close already does.