@domeadev/react-disclosure
v0.0.1
Published
A lightweight, flexible React disclosure (show/hide) component and hook library built with TypeScript. Perfect for building toggleable UI elements like dropdowns, modals, accordions, and more.
Maintainers
Readme
@domeadev/react-disclosure
A lightweight, flexible React disclosure (show/hide) component and hook library built with TypeScript. Perfect for building toggleable UI elements like dropdowns, modals, accordions, and more.
Features
- 🎯 Simple API - Easy-to-use component and hook APIs
- 🔄 Controlled & Uncontrolled - Support for both controlled and uncontrolled states
- 🎨 Flexible Composition - Composable components using Radix UI Slot pattern
- 📦 Tiny Bundle Size - Minimal dependencies
- 💪 TypeScript - Full type safety out of the box
- ✅ Well Tested - Comprehensive test coverage
Installation
npm
npm install @domeadev/react-disclosurepnpm
pnpm add @domeadev/react-disclosureyarn
yarn add @domeadev/react-disclosureUsage
Component API
The component-based approach provides a declarative way to manage disclosure state:
import { Disclosure } from "@domeadev/react-disclosure";
function App() {
return (
<Disclosure>
<Disclosure.Toggle>
<button>Toggle Content</button>
</Disclosure.Toggle>
<Disclosure.Opened>
<div>
<p>This content can be shown or hidden!</p>
<Disclosure.Cancel>
<button>Close</button>
</Disclosure.Cancel>
</div>
</Disclosure.Opened>
</Disclosure>
);
}Alternative: Using State Render Prop
You can also use the State component for more control:
import { Disclosure } from "@domeadev/react-disclosure";
function App() {
return (
<Disclosure>
<Disclosure.Toggle>
<button>Toggle Content</button>
</Disclosure.Toggle>
<Disclosure.State>
{(open) =>
open && (
<div>
<p>This content can be shown or hidden!</p>
<Disclosure.Cancel>
<button>Close</button>
</Disclosure.Cancel>
</div>
)
}
</Disclosure.State>
</Disclosure>
);
}Controlled Mode
import { Disclosure } from "@domeadev/react-disclosure";
import { useState } from "react";
function ControlledExample() {
const [open, setOpen] = useState(false);
return (
<Disclosure open={open} onOpenChange={setOpen}>
<Disclosure.Toggle>
<button>Toggle</button>
</Disclosure.Toggle>
<Disclosure.Opened>
<div>Content</div>
</Disclosure.Opened>
</Disclosure>
);
}Component Props
Disclosure (Root)
open?: boolean- Controlled open statedefaultOpen?: boolean- Default open state for uncontrolled mode (default:false)onOpenChange?: (open: boolean) => void- Callback when open state changes
Disclosure.Trigger
asChild?: boolean- Merge props into child element (default:true)- Opens the disclosure (sets state to
true)
Disclosure.Cancel
asChild?: boolean- Merge props into child element (default:true)- Closes the disclosure (sets state to
false)
Disclosure.Toggle
asChild?: boolean- Merge props into child element (default:true)- Toggles the disclosure state
Disclosure.State
children: (open: boolean) => ReactNode- Render prop that receives the current open state
Disclosure.Opened
children?: ReactNode- Content to show when disclosure is openfallback?: ReactNode- Content to show when disclosure is closed (default:null)
Disclosure.Closed
children?: ReactNode- Content to show when disclosure is closedfallback?: ReactNode- Content to show when disclosure is open (default:null)
Hook API
For more flexibility, use the useDisclosure hook:
import { useDisclosure } from "@domeadev/react-disclosure";
function HookExample() {
const [open, toggle] = useDisclosure(false);
return (
<div>
<button onClick={() => toggle()}>Toggle</button>
<button onClick={() => toggle(true)}>Open</button>
<button onClick={() => toggle(false)}>Close</button>
{open && <div>Content is visible!</div>}
</div>
);
}Context Hooks
Access disclosure state from within the component tree:
import {
Disclosure,
useDisclosureContext,
useOpenContext,
useToggleContext,
} from "@domeadev/react-disclosure";
function CustomComponent() {
const [open, toggle] = useDisclosureContext();
// or use them separately:
// const open = useOpenContext();
// const toggle = useToggleContext();
return <button onClick={() => toggle()}>{open ? "Close" : "Open"}</button>;
}
function App() {
return (
<Disclosure>
<CustomComponent />
<Disclosure.State>
{(open) => open && <div>Content</div>}
</Disclosure.State>
</Disclosure>
);
}API Reference
Functions
useDisclosure(defaultOpen?: boolean): [boolean, ToggleOpen]- Hook for managing disclosure stateuseDisclosureContext(): [boolean, ToggleOpen]- Access disclosure context (must be used withinDisclosure)useOpenContext(): boolean- Access only the open stateuseToggleContext(): ToggleOpen- Access only the toggle function
Types
type ToggleOpen = (open?: boolean) => void;
interface DisclosureProviderProps {
open?: boolean;
defaultOpen?: boolean;
onOpenChange?: (open: boolean) => void;
children?: ReactNode;
}
interface DisclosureActionProps extends SlotProps {
asChild?: boolean; // default: true
}Examples
Modal Dialog
import { Disclosure } from "@domeadev/react-disclosure";
function Modal() {
return (
<Disclosure>
<Disclosure.Trigger>
<button>Open Modal</button>
</Disclosure.Trigger>
<Disclosure.Opened>
<div className="modal-overlay">
<div className="modal">
<h2>Modal Title</h2>
<p>Modal content goes here</p>
<Disclosure.Cancel>
<button>Close</button>
</Disclosure.Cancel>
</div>
</div>
</Disclosure.Opened>
</Disclosure>
);
}Accordion
import { Disclosure } from "@domeadev/react-disclosure";
function Accordion() {
return (
<div>
<Disclosure>
<Disclosure.Toggle>
<button>Section 1</button>
</Disclosure.Toggle>
<Disclosure.Opened>
<div>Section 1 content</div>
</Disclosure.Opened>
</Disclosure>
<Disclosure>
<Disclosure.Toggle>
<button>Section 2</button>
</Disclosure.Toggle>
<Disclosure.Opened>
<div>Section 2 content</div>
</Disclosure.Opened>
</Disclosure>
</div>
);
}Toggle Button with Different States
import { Disclosure } from "@domeadev/react-disclosure";
function ToggleButton() {
return (
<Disclosure>
<Disclosure.Toggle>
<button>
<Disclosure.Opened>Hide</Disclosure.Opened>
<Disclosure.Closed>Show</Disclosure.Closed>
{" Details"}
</button>
</Disclosure.Toggle>
<Disclosure.Opened>
<div>Detailed information is now visible!</div>
</Disclosure.Opened>
</Disclosure>
);
}Dropdown Menu
import { useDisclosure } from "@domeadev/react-disclosure";
function Dropdown() {
const [open, toggle] = useDisclosure();
return (
<div className="dropdown">
<button onClick={() => toggle()}>Menu {open ? "▲" : "▼"}</button>
{open && (
<ul className="dropdown-menu">
<li onClick={() => toggle(false)}>Item 1</li>
<li onClick={() => toggle(false)}>Item 2</li>
<li onClick={() => toggle(false)}>Item 3</li>
</ul>
)}
</div>
);
}License
MIT © domeafavour
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
