Standard component library for Uniweb foundations. Tree-shakeable utilities, components, and hooks for building foundation components.
npm install @uniweb/kitKit is designed to be bundled into your foundation (not externalized like @uniweb/core). This means:
- Only what you use is bundled — Import 3 components? Only those 3 end up in your foundation
- No runtime overhead — Unused code is eliminated at build time
- Customizable — Override or extend any component without carrying dead code
- Small foundations — A minimal foundation using just
LinkanduseWebsitestays tiny
// vite.config.js - Kit is bundled, core is externalexportdefault{build: {rollupOptions: {external: ['react','react-dom','react-router-dom','@uniweb/core']// Note: @uniweb/kit is NOT in external — it gets tree-shaken}}}import{Link,Image,useWebsite}from'@uniweb/kit'functionHero({ content }){const{ localize }=useWebsite()return(<div><Imagesrc={content.images[0]?.url}alt="Hero"/><h1>{localize({en: 'Welcome',es: 'Bienvenido'})}</h1><Linkto="/about">Learn More</Link></div>)}Smart link component with routing, downloads, and auto-generated accessible titles.
import{Link}from'@uniweb/kit'<Linkto="/about">About</Link><Linkhref="https://github.com">GitHub</Link><Linkhref="/files/report.pdf">Download Report</Link><Linkhref="mailto:hello@example.com">Contact</Link>| Prop | Type | Description |
|---|---|---|
to / href | string | Destination URL |
title | string | Tooltip (auto-generated if omitted) |
target | string | Link target |
download | boolean | Force download behavior |
Versatile image component with filters and profile integration.
import{Image}from'@uniweb/kit'<Imagesrc="/photo.jpg"alt="Photo"/><Imagesrc="/photo.jpg"filter={{grayscale: 100}}/><Imageprofile={profile}type="avatar"size="lg"rounded/>| Prop | Type | Description |
|---|---|---|
src / url | string | Image URL |
alt | string | Alt text |
size | string | Preset: xs, sm, md, lg, xl, 2xl, full |
rounded | boolean|string | Border radius |
filter | object | CSS filters: blur, brightness, contrast, grayscale, saturate, sepia |
profile | object | Profile for avatar/banner images |
type | string | Image type: avatar, banner |
Safely render HTML with topic link resolution.
import{SafeHtml}from'@uniweb/kit'<SafeHtmlvalue="<p>Hello <strong>World</strong></p>"/><SafeHtmlvalue='<a href="topic:about">About</a>'/>SVG icon component with built-in icons and URL loading.
import{Icon}from'@uniweb/kit'<Iconname="check"size="24"color="green"/><Iconurl="/icons/custom.svg"/><Iconsvg="<svg>...</svg>"/>Built-in: check, alert, user, heart, settings, star, close, menu, chevronDown, chevronRight, externalLink, download, play
Social media platform icons with automatic detection.
import{SocialIcon,getSocialPlatform,filterSocialLinks}from'@uniweb/kit'<SocialIconplatform="twitter"size={24}/><SocialIconurl="https://twitter.com/example"/>// UtilitiesgetSocialPlatform('https://linkedin.com/in/user')// 'linkedin'filterSocialLinks(links)// Filter to only social linksSupported: facebook, twitter, x, linkedin, instagram, youtube, github, medium, pinterest, tiktok, discord, mastodon, bluesky, email, phone, orcid, researchgate, googlescholar
Smart typography components for rendering semantic parser output.
import{Text,H1,H2,P,PlainText}from'@uniweb/kit'<H1text="Main Title"/><H2text={["Multi-line","Subtitle"]}/><Ptext="A paragraph of content"/><Ptext={["First paragraph","Second paragraph"]}/>// Plain text (HTML shown as text)<PlainTexttext="Show <strong>tags</strong> as text"/>| Prop | Type | Description |
|---|---|---|
text | string|string[] | Content to render |
as | string | Tag: 'h1'-'h6', 'p', 'div', 'span' |
html | boolean | Render as HTML (default: true) |
lineAs | string | Tag for array items |
Aliases: H1, H2, H3, H4, H5, H6, P, Span, Div, PlainText
Video player for YouTube, Vimeo, and local videos.
import{Media}from'@uniweb/kit'<Mediasrc="https://youtube.com/watch?v=abc123"/><Mediasrc="/videos/intro.mp4"controls/><Mediasrc="https://youtube.com/..."thumbnail="/poster.jpg"facade/>File type icons based on filename.
import{FileLogo}from'@uniweb/kit'<FileLogofilename="report.pdf"size="32"/>Platform icons (YouTube, Vimeo, etc.).
import{MediaIcon}from'@uniweb/kit'<MediaIcontype="youtube"size="24"/>File preview with download functionality.
import{Asset}from'@uniweb/kit'<Assetvalue="document.pdf"profile={profile}/>Access website instance and utilities.
import{useWebsite}from'@uniweb/kit'functionMyComponent(){const{
website,// Website instance
localize,// Localize multilingual values
makeHref,// Transform hrefs (topic:, locale prefixes)
getLanguage,// Current language code
getLanguages // Available languages}=useWebsite()return<div>{localize({en: 'Hello',fr: 'Bonjour'})}</div>}Detect active navigation state.
import{useActiveRoute}from'@uniweb/kit'functionNavLink({ page }){const{ isActive, isActiveOrAncestor }=useActiveRoute()return(<Linkto={page.route}className={isActiveOrAncestor(page) ? 'font-bold' : ''}>{page.title}</Link>)}Detect scroll position for sticky headers.
import{useScrolled}from'@uniweb/kit'functionHeader(){constscrolled=useScrolled(50)// Threshold in pixelsreturn(<headerclassName={scrolled ? 'shadow-md' : ''}>
...
</header>)}Mobile menu state management.
import{useMobileMenu}from'@uniweb/kit'functionNavbar(){const{ isOpen, toggle, close }=useMobileMenu()return(<><buttononClick={toggle}>Menu</button>{isOpen&&<MobileMenuonClose={close}/>}</>)}Accordion/FAQ state management.
import{useAccordion}from'@uniweb/kit'functionFAQ({ items }){const{ isOpen, toggle }=useAccordion()returnitems.map((item,i)=>(<divkey={i}><buttononClick={()=>toggle(i)}>{item.question}</button>{isOpen(i)&&<p>{item.answer}</p>}</div>))}Viewport intersection detection for lazy loading and animations.
import{useInView,useIsInView}from'@uniweb/kit'functionAnimatedSection(){const{ ref, inView }=useInView({threshold: 0.2,once: true})return(<divref={ref}className={inView ? 'animate-fade-in' : 'opacity-0'}>
Content appears when scrolled into view
</div>)}// Simple boolean versionfunctionLazyImage({ src }){const[ref,isInView]=useIsInView()return<divref={ref}>{isInView&&<imgsrc={src}/>}</div>}Responsive grid utilities.
import{useGridLayout,getGridClasses}from'@uniweb/kit'functionGallery({ items }){const{ columns }=useGridLayout(items.length,{maxColumns: 4})return(<divclassName={getGridClasses(columns)}>{items.map(item=><Cardkey={item.id}{...item}/>)}</div>)}Access site theming data at runtime.
import{useThemeData,useThemeColor,useThemeColorVar,useColorContext,useAppearance}from'@uniweb/kit'functionThemedComponent({ block }){// Full theme accessconsttheme=useThemeData()constpalettes=theme?.getPaletteNames()// ['primary', 'secondary', ...]// Get specific colorconstprimaryColor=useThemeColor('primary',500)// '#3b82f6'constprimaryVar=useThemeColorVar('primary',600)// 'var(--primary-600)'// Context-aware (light/medium/dark sections)constcontext=useColorContext(block)// 'light' | 'medium' | 'dark'// Dark modeconst{ scheme, toggle, canToggle }=useAppearance()return(<divstyle={{color: primaryColor}}>{canToggle&&(<buttononClick={toggle}>{scheme==='dark' ? 'Light' : 'Dark'}</button>)}</div>)}Full-text search powered by Fuse.js. Requires fuse.js as a peer dependency in your foundation.
npm install fuse.jsMain search hook with debouncing and state management.
import{useSearch,useWebsite}from'@uniweb/kit'functionSearchComponent(){const{ website }=useWebsite()const{ query, results, isLoading, isEnabled, preload }=useSearch(website)if(!isEnabled)returnnullreturn(<div><inputonChange={e=>query(e.target.value)}placeholder="Search..."/>{isLoading&&<span>Searching...</span>}{results.map(r=>(<akey={r.id}href={r.href}>{r.title}</a>))}</div>)}Intent-based preloading — loads search index on hover/focus instead of page load.
import{useSearchWithIntent,useSearchShortcut}from'@uniweb/kit'functionSearchButton({ onClick }){const{ website }=useWebsite()const{ triggerPreload, intentProps }=useSearchWithIntent(website)// Cmd/Ctrl+K shortcut with preloaduseSearchShortcut({onOpen: onClick,onPreload: triggerPreload,})return(<buttononClick={onClick}{...intentProps}>
Search
</button>)}This saves bandwidth — the search index only loads when users show intent to search.
Keyboard shortcut for opening search.
import{useSearchShortcut}from'@uniweb/kit'// SimpleuseSearchShortcut(()=>setSearchOpen(true))// With preload on shortcutuseSearchShortcut({onOpen: ()=>setSearchOpen(true),onPreload: ()=>searchClient.preload()})Low-level search client for advanced use.
import{createSearchClient}from'@uniweb/kit'constclient=createSearchClient(website,{fuseOptions: {threshold: 0.3},defaultLimit: 10})// Query — returns SearchResult[]constresults=awaitclient.query('authentication',{limit: 5})// Same query, plus how many matched before `limit` — the 47 in "showing 10 of 47".// `total` is null when the active provider cannot say (a deployment fact, not an// error): the local index always knows it; an endpoint knows it only if it// reports one. Render the count conditionally, the results unconditionally.const{results: page, total }=awaitclient.queryWithTotal('authentication',{limit: 5})// Preload indexawaitclient.preload()// Check statusclient.isEnabled()client.getIndexUrl()Pre-styled components with Tailwind CSS.
import{Section,SidebarLayout,Disclaimer}from'@uniweb/kit'<Sectionwidth="lg"padding="md"className="bg-gray-50"><h1>Welcome</h1></Section><SidebarLayoutsidebar={<Nav/>}sidebarPosition="left"><main>Content</main></SidebarLayout><Disclaimertitle="Terms of Service"content="<p>Please read our terms...</p>"triggerText="View Terms"/>import{cn,stripTags,isExternalUrl,isFileUrl,detectMediaType}from'@uniweb/kit'// Merge Tailwind classes (uses tailwind-merge)cn('px-4 py-2','bg-blue-500',condition&&'opacity-50')// Strip HTML tagsstripTags('<p>Hello</p>')// "Hello"// URL utilitiesisExternalUrl('https://google.com')// trueisFileUrl('/files/doc.pdf')// truedetectMediaType('https://youtube.com/...')// 'youtube'┌─────────────────────────────────────────────────────────────┐
│ Foundation (your code) │
│ ├── imports @uniweb/kit (bundled, tree-shaken) │
│ └── @uniweb/core marked as external │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ @uniweb/runtime (browser) │
│ ├── Loads foundation dynamically │
│ ├── Provides @uniweb/core singleton │
│ └── Orchestrates React rendering │
└─────────────────────────────────────────────────────────────┘
Kit: Different foundations may use different subsets of kit. Tree-shaking ensures each foundation only includes what it uses.
Core: Contains the Website, Page, and Block classes that must be singletons. The runtime provides these — foundations reference them via the external import.
Apache-2.0