Quick Start
This guide will help you build your first application using Zayne Labs Toolkit. We’ll create a simple interactive component that demonstrates core utilities, React hooks, and type safety.
What We’ll Build
A toggle component with clipboard functionality that showcases:
Core utilities (copyToClipboard, debounce)
React hooks (useToggle, useDisclosure, useClickOutside)
Type safety with TypeScript
Install the packages
First, install the packages you need: npm install @zayne-labs/toolkit-core @zayne-labs/toolkit-react @zayne-labs/toolkit-type-helpers
Make sure you have React 19.0.0 or higher installed in your project.
Create your first component
Create a new file InteractiveCard.tsx and add the following code: import { copyToClipboard } from "@zayne-labs/toolkit-core" ;
import { useToggle , useDisclosure } from "@zayne-labs/toolkit-react" ;
import { useState } from "react" ;
import type { Prettify } from "@zayne-labs/toolkit-type-helpers" ;
type CardState = Prettify <{
isExpanded : boolean ;
copyCount : number ;
}>;
export function InteractiveCard () {
const [ isExpanded , toggleExpanded ] = useToggle ( false );
const [ copyCount , setCopyCount ] = useState ( 0 );
const modal = useDisclosure ({
initialState: false ,
hasScrollControl: true ,
});
const handleCopy = async () => {
await copyToClipboard ( "Hello from Zayne Labs Toolkit!" , {
onSuccess : () => {
setCopyCount (( prev ) => prev + 1 );
console . log ( "Copied to clipboard!" );
},
onError : ( error ) => {
console . error ( "Failed to copy:" , error );
},
});
};
return (
< div className = "card" >
< h2 > Interactive Card </ h2 >
< button onClick = {() => toggleExpanded ()} >
{ isExpanded ? "Collapse" : "Expand" }
</ button >
{ isExpanded && (
< div className = "content" >
< p > This content is toggleable !</ p >
< button onClick = { handleCopy } >
Copy to Clipboard
</ button >
{ copyCount > 0 && (
< p > Copied { copyCount } time { copyCount > 1 ? "s" : "" }!</ p >
)}
</ div >
)}
< button onClick = {() => modal.onOpen()} >
Open Modal
</ button >
{ modal . isOpen && (
< div className = "modal" >
< h3 > Modal is Open </ h3 >
< p > Scroll is locked when modal is open </ p >
< button onClick = {() => modal.onClose()} >
Close Modal
</ button >
</ div >
)}
</ div >
);
}
This component demonstrates:
useToggle for expandable content
copyToClipboard with success/error callbacks
useDisclosure with scroll lock for modals
Prettify type helper for clean type definitions
Use advanced hooks
Let’s enhance the component with more hooks. Create AdvancedCard.tsx: import { debounce } from "@zayne-labs/toolkit-core" ;
import {
useClickOutside ,
useCallbackRef ,
useDebounce
} from "@zayne-labs/toolkit-react" ;
import { composeRefs } from "@zayne-labs/toolkit-react/utils" ;
import { useRef , useState } from "react" ;
export function AdvancedCard () {
const [ search , setSearch ] = useState ( "" );
const [ isMenuOpen , setIsMenuOpen ] = useState ( false );
const menuRef = useRef < HTMLDivElement >( null );
const inputRef = useRef < HTMLInputElement >( null );
// Debounce search input
const debouncedSearch = useDebounce ( search , 300 );
// Close menu when clicking outside
const handleClickOutside = useCallbackRef (() => {
setIsMenuOpen ( false );
});
useClickOutside ( menuRef , handleClickOutside , {
enabled: isMenuOpen ,
});
return (
< div className = "advanced-card" >
< input
ref = { inputRef }
type = "text"
value = { search }
onChange = {(e) => setSearch (e.target.value)}
placeholder = "Search..."
/>
< p > Debounced value : { debouncedSearch }</ p >
< button onClick = {() => setIsMenuOpen (! isMenuOpen )} >
Toggle Menu
</ button >
{ isMenuOpen && (
< div ref = { menuRef } className = "menu" >
< p > Click outside to close </ p >
< ul >
< li > Menu Item 1</ li >
< li > Menu Item 2</ li >
< li > Menu Item 3</ li >
</ ul >
</ div >
)}
</ div >
);
}
This demonstrates:
useDebounce for search input optimization
useClickOutside for dropdown menus
useCallbackRef for stable callbacks
Ref composition with composeRefs
Use React utilities
The toolkit provides powerful React utilities. Here’s an example using slot components: import {
createSlotComponent ,
getSlotMap ,
composeEventHandlers ,
type GetSlotComponentProps ,
} from "@zayne-labs/toolkit-react/utils" ;
type DialogSlots =
| GetSlotComponentProps < "header" >
| GetSlotComponentProps < "content" >
| GetSlotComponentProps < "footer" >;
function Dialog ( props : { children : React . ReactNode }) {
const { children } = props ;
const slots = getSlotMap < DialogSlots >( children );
const handleClick = composeEventHandlers (
() => console . log ( "Dialog clicked" ),
() => console . log ( "Additional handler" )
)();
return (
< div className = "dialog" onClick = { handleClick } >
< header >{slots. header } </ header >
< div className = "content" > {slots. content } </ div >
< footer >{slots. footer } </ footer >
< aside >{slots. default } </ aside >
</ div >
);
}
Dialog . Slot = createSlotComponent < DialogSlots >();
// Usage
export function DialogExample () {
return (
< Dialog >
< Dialog . Slot name = "header" >
< h2 > Dialog Title </ h2 >
</ Dialog . Slot >
< Dialog . Slot name = "content" >
< p > This is the dialog content </ p >
</ Dialog . Slot >
< Dialog . Slot name = "footer" >
< button > Close </ button >
</ Dialog . Slot >
< p > This goes in the default slot </ p >
</ Dialog >
);
}
Use type helpers
Leverage TypeScript utilities for better type safety: import type {
Prettify ,
DeepPrettify ,
NonFalsy ,
PrettyOmit ,
CallbackFn ,
} from "@zayne-labs/toolkit-type-helpers" ;
import { isString , isBoolean , isNumber } from "@zayne-labs/toolkit-type-helpers" ;
// Clean up intersection types
type User = Prettify <{ id : number } & { name : string } & { email : string }>;
// Result: { id: number; name: string; email: string }
// Deep prettify nested objects
type NestedData = DeepPrettify <{
user : { id : number } & { profile : { name : string } };
}>;
// Remove falsy types
type NonFalsyString = NonFalsy < string | null | undefined >; // string
// Omit with prettified result
type UserWithoutEmail = PrettyOmit < User , "email" >;
// Type-safe callbacks
const handleUserUpdate : CallbackFn < User > = ( user ) => {
console . log ( user . name );
};
// Runtime type guards
function processValue ( value : unknown ) {
if ( isString ( value )) {
// TypeScript knows value is string here
return value . toUpperCase ();
}
if ( isNumber ( value )) {
// TypeScript knows value is number here
return value . toFixed ( 2 );
}
if ( isBoolean ( value )) {
// TypeScript knows value is boolean here
return value ? "yes" : "no" ;
}
return "unknown" ;
}
Run your application
Add the components to your main app: import { InteractiveCard } from "./InteractiveCard" ;
import { AdvancedCard } from "./AdvancedCard" ;
import { DialogExample } from "./SlotExample" ;
export default function App () {
return (
< div className = "app" >
< h1 > Zayne Labs Toolkit Demo </ h1 >
< InteractiveCard />
< AdvancedCard />
< DialogExample />
</ div >
);
}
Start your development server and test the components!
Common Patterns
Debouncing and Throttling
import { debounce , throttle } from "@zayne-labs/toolkit-core" ;
import { useDebounce , useThrottle } from "@zayne-labs/toolkit-react" ;
// Core utilities
const debouncedFn = debounce (( value : string ) => {
console . log ( "Debounced:" , value );
}, 300 );
const throttledFn = throttle (( value : string ) => {
console . log ( "Throttled:" , value );
}, 1000 );
// React hooks
function SearchComponent () {
const [ search , setSearch ] = useState ( "" );
const debouncedSearch = useDebounce ( search , 300 );
const throttledSearch = useThrottle ( search , 1000 );
// Use debouncedSearch for API calls
// Use throttledSearch for analytics
}
State Management
import { createStore } from "@zayne-labs/toolkit-core" ;
import { useStore } from "@zayne-labs/toolkit-react" ;
// Create a store
const counterStore = createStore ({ count: 0 });
// Use in React
function Counter () {
const count = useStore ( counterStore , ( state ) => state . count );
return (
< button onClick = {() => counterStore.setState({ count : count + 1 })} >
Count : { count }
</ button >
);
}
Next Steps
Core Utilities Explore all available core utilities.
React Hooks Discover all React hooks.
Type Helpers Learn about TypeScript utilities.
API Reference View the complete API reference.
All utilities are tree-shakeable. Your bundler will only include what you actually use, keeping your bundle size minimal.
Best Practices
Import Specific Utilities : Import only what you need for optimal tree-shaking
// Good
import { useToggle , useDisclosure } from "@zayne-labs/toolkit-react" ;
// Avoid
import * as toolkit from "@zayne-labs/toolkit-react" ;
Use Type Helpers : Leverage TypeScript utilities for cleaner types
type Props = Prettify < BaseProps & AdditionalProps >;
Combine Hooks : Hooks are composable and work well together
const modal = useDisclosure ();
const [ data , setData ] = useStorageState ( "key" , defaultValue );
Leverage Callbacks : Use useCallbackRef for stable function references
const handleClick = useCallbackRef (() => {
// Always gets latest closure values
});