skin-material
A Material Design skin for Fluixi UI, activate with data-ui="material".
Restyles the components to Material 3: pill buttons, the baseline palette in light and
dark, tonal surfaces that rise by colour as well as by shadow, filled text fields with an
underline, a state layer on every interactive element, and self-hosted Roboto. It composes
with the data-theme and data-accent axes: an accent other than blue
replaces the M3 primary, and high-contrast keeps the token palette.
Installation
pnpm add @fluixi-ui/skin-material
Usage
Import the stylesheet after the tokens + preset, then set data-ui="material":
import '@fluixi-ui/styles/all.css';
import '@fluixi-ui/skin-material/styles.css';
document.documentElement.dataset.ui = 'material';
Or drive it reactively, lazy-loading the CSS only when the skin is active:
import { createTheme } from '@fluixi/core';
const skin = createTheme({
attribute: 'data-ui',
themes: ['fluixi', 'material'],
default: 'fluixi',
load: (s) => s === 'material' && import('@fluixi-ui/skin-material/styles.css'),
});
skin.init();
The ripple
The CSS state layer covers hover / focus / press, but a true click-origin ripple
needs the pointer position, so it's a tiny JS primitive. Call installRipple
once; it delegates a single pointerdown listener that spawns the ripple inside
any Material control:
import { installRipple } from '@fluixi-ui/skin-material/ripple';
installRipple(); // returns a disposer
What it restyles
- Buttons, 40px pills with a 14px medium label.
solidis flat at rest and rises to level 1 on hover;softis the tonal button,outlinea transparent pill with an outline edge,ghostthe text button. State shows as a currentColor layer (8% hover, 12% focus and press) and never as scale. - Icon buttons and FABs, 40px circles; FABs on the primary container with a 16px corner, 96px for the large size.
- Selection controls, the 52x32 switch whose thumb grows from 16px to 24px when checked and to 28px when pressed; 18px checkbox and 20px radio; a 4px tonal slider track. Each shows a 40px state layer behind it.
- Fields, filled by default (container fill, 4px top corners, an underline that turns
2px primary on focus), or outlined (a 4px box with a 2px primary edge on focus). 56px high.
With
data-ui-corner="round"a filled field becomes the search bar's capsule, with a ring inside it for focus and errors in place of the underline. - Menus and lists, 4px containers with full-bleed rows.
- Surfaces, tonal elevation: cards on the low container, menus on the container, dialogs
on the high container with 28px corners.
Surfaceelevations 0 to 4 step through the container colours with their shadow level. - Tabs, a 3px primary indicator with a rounded top. Chips have 8px corners. Toasts are snackbars on the inverse surface.
How it works
All rules live in the flx.skin cascade layer, which sits above
flx.components (the default look), so they win wherever they match, while your
CSS stays unlayered and wins over both. Everything is scoped to
[data-ui="material"], so the skin only applies where you opt in.
Part of the Fluixi UI component library. Made with ☕ by the Fluixi team.