Live previews and full props for every component, in both frameworks. This README is the map; each package has a quick start of its own.
Plass is one design language, shipped as two libraries. 127 components made of tinted glass and gradients, in React and in Flutter, under the same names and the same numbers. React adds three more for problems only the DOM has.
Every surface answers one question: is this pressed, or does it hold something? A thing you press is a tinted pane, filled with a gradient that turns through its colour family and lit by a bloom that follows your pointer. A thing that holds something is clear glass: translucent, deeply blurred, never dyed. Nothing is bevelled or embossed, and depth is carried by light, colour and blur.
- Finished when you install it. The gradients, shadows, blur, focus ring and press response are already decided and already agree with each other. There is no theme file to fill in.
- Learn it once, use it on both. An
mdcontrol is 40px in either framework,primaryis the same colour family, and one documentation page covers the two. - Five props, not fifty.
size,color,variant,densityandelevationmean the same thing on every component, so the tenth one costs nothing to learn after the first. - Readable because it was measured. Every gradient stop clears 4.5:1 against its own label, the lightest corner included.
- Accessible without the checklist. Roles, labels, keyboard operation and focus management live inside the components.
- Dark mode you do not write. It follows the platform and can be forced either way on any subtree.
- Nothing you did not ask for. The npm package is ESM and tree-shakeable, so only what you import is bundled. The pub package has no dependencies at all.
| Package | Registry | Requires | Quick start |
|---|---|---|---|
packages/react |
npm: plass-ui |
React 18 or 19, Node.js 20.19 or later | README |
packages/flutter |
pub.dev: plass_ui |
Flutter 3.41 or newer (Dart 3.11) | README |
The two version independently and keep separate changelogs. packages/react/CHANGELOG.md is the React package's, packages/flutter/CHANGELOG.md the Flutter one's. A release on one side is not a release on the other, so the numbers will not always agree.
npm install plass-ui/* your app's CSS entry point */
@import "plass-ui/styles.css";import { PlButton, PlTextField } from 'plass-ui';
<PlTextField label="Email" type="email" fullWidth />
<PlButton type="submit">Sign in</PlButton>
<PlButton variant="glass" color="secondary">Cancel</PlButton>react and react-dom are peer dependencies, React 18 or 19. The stylesheet is finished CSS: Tailwind CSS v4 builds this package and does not have to be installed in yours, though there is a second entry point for a project that already runs it. Every component has an entry point of its own (plass-ui/button) and nearly all of them carry 'use client', so a Next.js Server Component can import one with nothing configured, and PlTable, whose columns are render callbacks, deliberately does not, so a server-rendered page can use its own API.
The React quick start has the rest.
flutter pub add plass_uiimport 'package:flutter/widgets.dart';
import 'package:plass_ui/plass_ui.dart';
PlButton(
onPressed: save,
child: const Text('Save'),
)Nothing else to install: no dependencies, no assets, no platform channels, no stylesheet and no provider. It is built on package:flutter/widgets.dart alone, so it drops into any Flutter app without bringing a second design system in behind it, and it is unaffected by material.dart and cupertino.dart moving out of the framework into material_ui and cupertino_ui.
The Flutter quick start has the rest.
This is the one setup step neither package can do for you, and skipping it is the fastest way to conclude the glass is broken. Plass draws controls and sheets; it does not paint your background, but a sheet of glass over a flat white page has nothing to be in front of, and every translucent surface will read as opaque. Two tokens exist for exactly this, and they are the same two on both sides:
body {
background: linear-gradient(160deg, var(--plass-bg-from) 0%, var(--plass-bg-to) 100%);
background-attachment: fixed;
color: var(--plass-fg);
}final tokens = PlassTheme.of(context);
DecoratedBox(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: <Color>[tokens.bgFrom, tokens.bgTo],
),
),
child: ...,
)Any backdrop with structure in it works. What does not work is nothing at all.
| Page | What you will find |
|---|---|
| Getting started | Install and setup, end to end, in either framework. |
| Examples | Whole screens built out of the components, a dashboard, a landing page, a sign-up flow. |
| All components | Every component, one page each: live previews and the full props table. |
| Design language | Why a Plass surface looks and behaves the way it does. |
| Prop conventions | The shared vocabulary every component draws from. |
| Colour | The token families, the measured contrast, and how to theme them. |
| Changelog | What changed in each release. |
Every component is exported under a Pl prefix. Button, Card and Table are the most-taken identifiers in the ecosystem, and a consumer should not have to alias ours on import.
The list below is both packages'. The props are the same props under Dart's names, and each component's page says exactly what differs.
A † marks a name that is React-only. PlFlex, PlPortal and PlVisuallyHidden are the three components React adds. They are not omissions. Each one answers a problem only the DOM has, and the Dart answer is a line of framework code rather than a component. Their pages say which.
The counts at the top of this page are one component per folder. The list also names two exports that are not counted, because each shares a folder and a page with another component: PlToggleGroup, beside PlToggle, and PlContextMenu, a second trigger onto PlMenu's surface. PlContextMenu is the fourth †, for a reason of its own: no right-click gesture means the same thing on every platform Flutter runs on, so a Flutter app opens a PlMenu from onLongPress itself.
PlAreaChart · PlBarChart · PlGaugeChart · PlHeatmapChart · PlLineChart · PlPieChart · PlScatterChart · PlSparkline · PlTimelineChart
PlAppLogo · PlAvatar · PlBadge · PlBlockquote · PlBreadcrumb · PlChip · PlCodeBlock · PlDataList · PlDataTable · PlDivider · PlGallery · PlHighlight · PlHotKeys · PlIcon · PlImage · PlList · PlMockup · PlStat · PlTable · PlTextLink · PlTimeline · PlTree · PlTypography · PlVisuallyHidden†
PlAlert · PlConfirmProvider · PlDrawer · PlEmpty · PlMeter · PlModal · PlOverlay · PlPopconfirm · PlPopover · PlProgressBox · PlProgressCircular · PlProgressLinear · PlSkeleton · PlToast · PlTooltip · PlTour
PlButton · PlButtonGroup · PlCalendar · PlCheckbox · PlColorPicker · PlCombobox · PlDatePicker · PlDateRangePicker · PlDateTimePicker · PlFieldset · PlFilePicker · PlFloatingActionButton · PlForm · PlIconButton · PlNumberField · PlOtpField · PlPagination · PlRadioGroup · PlRating · PlSegmentedButton · PlSelect · PlSlider · PlSwitch · PlTextField · PlTimePicker · PlToggle · PlToggleGroup · PlTransfer · PlTreeSelect
PlAspectRatio · PlContainer · PlFlex† · PlFooter · PlGrid · PlHeader · PlPageLayout · PlPanes · PlPortal† · PlScrollArea · PlScrollZone · PlShow · PlSidebar · PlStack
PlAnchor · PlBackTop · PlBottomNavigation · PlCommandPalette · PlContextMenu† · PlFloatingBottomNavigation · PlMenu · PlMenubar · PlNavigationMenu · PlStepper
PlAccordion · PlBox · PlCard · PlCarousel · PlChatBubble · PlCollapsible · PlHoverCard · PlHowToSteps · PlPill · PlSpoiler · PlTabs · PlToolbar · PlWindowPane
PlAnimateAppear · PlAnimateBlink · PlAnimateCounter · PlAnimateFade · PlAnimateFloat · PlAnimateGrow · PlAnimateHeadline · PlAnimateLighting · PlAnimateMarquee · PlAnimateReveal · PlAnimateRotate · PlAnimateScramble · PlAnimateShake · PlAnimateSlide · PlAnimateSplit · PlAnimateTyping · PlAnimateZoom
size, color, density and the date vocabulary can be decided once for an application rather than at every call site. Optional. The library is finished without it.
import { PlassProvider } from "plass-ui";
<PlassProvider size="sm" density="compact" locale="ko-KR">
<App />
</PlassProvider>;It deliberately does not set variant or elevation: those name what a surface is made of and how far off the page it sits, and both are decided per component by the design language. A button is solid and rests on the sheet, a field is cut into it. The guide has the long version, and the precedence: a component's own prop beats the set it is in, which beats the provider.
The Flutter package does the same through PlassTheme.merge, which also carries the date vocabulary. names and labels are what a locale is there, since the framework ships no Intl.
React-only, and the machinery the library already ran on rather than anything new. Import them from the barrel or from plass-ui/hooks.
| Hook | What it answers |
|---|---|
usePlMediaQuery |
Whether the window matches a CSS media query, re-rendering when it stops |
usePlBreakpoint |
Which rung of the breakpoint ladder the window is on |
usePlBreakpointValue |
What a PlassResponsive map resolves to at that rung |
usePlReducedMotion |
Whether the reader has asked their platform for less movement |
usePlHotKeys |
Binds keyboard chords, spelled the way PlHotKeys draws them |
usePlColorScheme |
The dark mode toggle, the choice, where it is kept, and what it writes |
usePlDisclosure |
One boolean and the four callbacks that change it, all of them stable |
usePlElementSize |
The size of an element's content box, kept up to date as it changes |
usePlOnScreen |
Whether an element has been seen, or is on screen now with once: false |
usePlassDefaults, usePlToast and usePlConfirm live with the part they belong to rather than in plass-ui/hooks. usePlassDefaults returns what the nearest PlassProvider decided, and is imported from the barrel or from plass-ui/provider. usePlToast raises a toast from a click handler under a PlToastProvider, and is imported from the barrel or from plass-ui/toast. usePlConfirm asks a question from a click handler under a PlConfirmProvider and waits for the answer, and is imported from the barrel or from plass-ui/confirm.
Flutter answers the same questions with framework calls (MediaQuery, PlassTheme) rather than with anything this package would add. Each hook's page names the Dart equivalent.
One design language, three things built out of it. Each is entered and run on its own. There is no install at the repository root and no root package.json.
cd packages/react
npm install
npm test # Vitest, three shards of headless Chromium
npm run typecheck # tsc --noEmit over both TS projects
npm run build # tsc + terser + build-styles → dist/
npm run lint # ESLintcd packages/flutter
flutter pub get
flutter test # Widget tests
flutter analyze
cd example && flutter run # The gallery, on any devicecd docs
npm install
npm run flutter:demos # Compiles the gallery into public/flutter (needs the Flutter SDK)
npm run dev # VitePress — the develop-and-eyeball loop
npm run build # Reuses public/flutter when a build is already thereThe site renders the React components from packages/react/src through a Vite alias and embeds the Flutter gallery as a frame per preview, so npm run dev is the develop-and-eyeball loop for both; there is no separate demo app. Editing a component shows up immediately on the React side. The Flutter side has to be rebuilt with npm run flutter:demos -- --force: without --force the script skips the build whenever public/flutter already holds one, and npm run build reuses that build the same way.
Anyone can contribute to the project by reporting new issues or submitting a pull request. CONTRIBUTING.md is the rest: where things live, and how a change to a component is expected to arrive. Participation is subject to the Code of Conduct.
To report a security issue, please follow the process described in SECURITY.md.
For anything else, reach the maintainers at cdget.com/contact.
MIT © CDGet

