@amauryuh/ui
v0.6.1
Published
Reusable React layout components, styled with Tailwind CSS v4
Maintainers
Readme
@amauryuh/ui
Reusable React components for building app layouts. Styled with Tailwind CSS v4.
Install
npm install @amauryuh/uiPeer dependencies: react (18+) and tailwindcss (v4).
Tailwind skips node_modules, so import the package's stylesheet after
Tailwind to have it generate the classes the components use:
@import "tailwindcss";
@import "@amauryuh/ui/styles.css";Layout
A full-screen app shell: a sidebar and a container that slide as two panes on
mobile and sit side by side from md up. The container's navigation and
footer float over a body with custom scrolling (momentum, rubber band,
smoothed wheel). On iOS the layout follows the visual viewport, so the footer
stays above the keyboard.
import { Layout, useLayout } from "@amauryuh/ui";
function App() {
return (
<Layout className="bg-slate-100">
<Layout.Sidebar className="md:w-80">…</Layout.Sidebar>
<Layout.Container>
<Layout.Navigation>…</Layout.Navigation>
<Layout.Body className="flex-col">…</Layout.Body>
<Layout.Footer>…</Layout.Footer>
<Layout.ScrollToTop />
</Layout.Container>
</Layout>
);
}Layout.SidebarActioncloses the sidebar on click (shouldOpenopens it).Layout.SidebarOpenandLayout.SidebarClosedrender their children only while the sidebar is open or closed, e.g. a back button on mobile. They follow the state, not the screen: frommdup both panes are always in view, so addmd:hiddento content that only makes sense on mobile.Layout.ScrollToTopis a round button floating above the footer that smooth-scrolls its container's body back to the top. It appears once the body is scrolled pastthresholdpx (default 200). PassclassNameto restyle or move it,childrento replace the icon andaria-labelto translate it.- Edge swipe: on mobile, a finger dragged from the container's left edge
past its middle (or flicked to the right) opens the sidebar, like in phone
apps. The address and history stay as they are. The panes follow the
finger. Touch only, never the mouse.
Turn it off with
<Layout edgeSwipe={false}>. Layout.ScrollToBottomis the same button for the other end, e.g. the newest message of a log. It shows once the body is further thanthresholdpx from its end.<Layout.Body stickToBottom>opens scrolled to the end and, while the reader is there, keeps the end in view as content is added or the body shrinks (e.g. the phone keyboard). Scrolling up lets go.useLayout()returns{ sidebarOpen, setSidebarOpen }.scrollBodyTo(element, top, { smooth })scrolls aLayout.Bodythrough its scroller, so it never fights finger or wheel momentum.scrollBodyIntoView(element, { smooth })scrolls the body holdingelementso it sits in the middle of what the bars leave visible.useLayoutBody()returns the scrolling element of the enclosing container's body (ornullbefore it renders).
On Android, add interactive-widget=resizes-content to the viewport meta tag
so the page shrinks above the keyboard.
Every part takes a className. It can restyle a part but not override the
classes the layout depends on.
Scrollable
A scrolling area with the body's scrolling (momentum, rubber band, smoothed
wheel, no scrollbar), e.g. the list in a sidebar. Give it a height, e.g.
flex-1 in a flex column:
import { Layout } from "@amauryuh/ui";
<Layout.Sidebar>
<div className="flex h-full flex-col">
<header>…</header>
<Layout.Scrollable aria-label="Items" className="flex-1">
<ul>…</ul>
</Layout.Scrollable>
</div>
</Layout.Sidebar>;className styles the scrolling box and contentClassName the content
inside it. Other props (aria-label, role, …) go on the box. Also
exported on its own as Scrollable.
On touch screens, dragging a part of the layout that doesn't scroll (a bar, a sidebar header) leaves the page still: the browser doesn't pan it. Pinch zoom, sideways drags in form fields (moving the caret) and boxes that scroll natively, along their axis, keep the browser's handling.
Scroller
The custom scrolling on its own, for any scrolling element:
import { useScroller } from "@amauryuh/ui";
const { wrapper, content } = useScroller();
<div ref={wrapper} className="overflow-y-auto">
<div ref={content}>…</div>
</div>;Development
npm install
npm run dev # playground at src/main.tsx
npm run build # library to dist/
npm publish # typechecks and builds firstComponents live in src/lib and are exported from src/lib/index.ts.
