@remix-run/ui
v0.1.1
Published
UI tokens, mixins, and glyphs for Remix components
Maintainers
Readme
ui
Runtime UI primitives for Remix apps, including the component runtime, server rendering, frame hydration, reusable mixins, first-party components, and theme tokens.
Features
- Component runtime APIs for rendering, hydration, frame navigation, and JSX
- Server rendering APIs for streaming Remix UI trees and frames
mixcomposition with event, ref, CSS, and animation helpers- First-party components such as buttons, menus, listboxes, popovers, and selects
- Fixed typed
themecontract whose leaves resolve tovar(--rmx-...) createTheme()andcreateGlyphSheet()utilities for shared app styling and glyphs
Installation
npm i remixUsage
Define your app theme once:
import { createTheme } from 'remix/ui'
let Theme = createTheme({
space: {
none: '0px',
px: '1px',
xs: '2px',
sm: '4px',
md: '8px',
lg: '12px',
xl: '16px',
xxl: '24px',
},
radius: {
none: '0px',
sm: '4px',
md: '8px',
lg: '12px',
xl: '16px',
full: '9999px',
},
fontSize: {
xxxs: '10px',
xxs: '11px',
xs: '12px',
sm: '14px',
md: '16px',
lg: '18px',
xl: '20px',
xxl: '28px',
},
lineHeight: {
tight: '1.2',
normal: '1.5',
relaxed: '1.7',
},
fontWeight: {
normal: '400',
medium: '500',
semibold: '600',
bold: '700',
},
shadow: {
xs: '0 1px 2px rgb(0 0 0 / 0.05)',
sm: '0 1px 3px rgb(0 0 0 / 0.10)',
md: '0 4px 10px rgb(0 0 0 / 0.12)',
lg: '0 10px 30px rgb(0 0 0 / 0.16)',
xl: '0 20px 50px rgb(0 0 0 / 0.20)',
},
zIndex: {
dropdown: '1000',
popover: '1100',
sticky: '1200',
overlay: '1300',
modal: '1400',
toast: '1500',
tooltip: '1600',
},
surface: {
lvl0: '#ffffff',
lvl1: '#f8fafc',
lvl2: '#f1f5f9',
lvl3: '#e5edf7',
lvl4: '#dbe6f4',
},
colors: {
text: {
primary: '#111827',
secondary: '#374151',
muted: '#6b7280',
link: '#2563eb',
},
border: {
subtle: '#e5e7eb',
default: '#d1d5db',
strong: '#9ca3af',
},
focus: {
ring: '#3b82f6',
},
overlay: {
scrim: 'rgb(0 0 0 / 0.45)',
},
action: {
primary: {
background: '#2563eb',
backgroundHover: '#1d4ed8',
backgroundActive: '#1e40af',
foreground: '#ffffff',
border: '#2563eb',
},
secondary: {
background: '#ffffff',
backgroundHover: '#f8fafc',
backgroundActive: '#f1f5f9',
foreground: '#111827',
border: '#d1d5db',
},
danger: {
background: '#dc2626',
backgroundHover: '#b91c1c',
backgroundActive: '#991b1b',
foreground: '#ffffff',
border: '#dc2626',
},
},
},
})Render the theme once near the top of your document:
function Layout(props: { children: RemixNode }) {
return (
<html>
<head>
<Theme />
</head>
<body>{props.children}</body>
</html>
)
}Consume the shared token contract from app code and first-party components:
import { css } from 'remix/ui'
import { theme } from 'remix/ui'
let card = css({
backgroundColor: theme.surface.lvl0,
color: theme.colors.text.primary,
border: `1px solid ${theme.colors.border.subtle}`,
borderRadius: theme.radius.md,
paddingInline: theme.space.md,
paddingBlock: theme.space.sm,
})
<div mix={card} />Render shared glyphs separately from the theme styles:
import type { RemixNode } from 'remix/ui'
import { Button } from '@remix-run/ui/button'
import { Glyph } from '@remix-run/ui/glyph'
import { RMX_01, RMX_01_GLYPHS } from '@remix-run/ui/theme'
function Layout(props: { children: RemixNode }) {
return (
<html>
<head>
<RMX_01 />
</head>
<body>
<RMX_01_GLYPHS />
<Button startIcon={<Glyph name="add" />} tone="primary">
New project
</Button>
{props.children}
</body>
</html>
)
}License
See LICENSE
