@dash-ui/react
Version:
React components and hooks for dash-ui
611 lines (475 loc) • 18.7 kB
Markdown
<hr>
<img src='https://github.com/dash-ui/styles/raw/main/assets/logo.png'/>
<blockquote>React components and hooks for <a href="https://github.com/dash-ui/styles">dash-ui</a></blockquote>
<pre>npm i @dash-ui/react</pre>
<a href="https://bundlephobia.com/result?p=@dash-ui/react">
<img alt="Bundlephobia" src="https://img.shields.io/bundlephobia/minzip/@dash-ui/react?style=for-the-badge&labelColor=24292e">
</a>
<a aria-label="Types" href="https://www.npmjs.com/package/@dash-ui/react">
<img alt="Types" src="https://img.shields.io/npm/types/@dash-ui/react?style=for-the-badge&labelColor=24292e">
</a>
<a aria-label="Code coverage report" href="https://codecov.io/gh/dash-ui/react">
<img alt="Code coverage" src="https://img.shields.io/codecov/c/gh/dash-ui/react?style=for-the-badge&labelColor=24292e">
</a>
<a aria-label="Build status" href="https://github.com/dash-ui/react/actions/workflows/release.yml">
<img alt="Build status" src="https://img.shields.io/github/workflow/status/dash-ui/react/release/main?style=for-the-badge&labelColor=24292e">
</a>
<a aria-label="NPM version" href="https://www.npmjs.com/package/@dash-ui/react">
<img alt="NPM Version" src="https://img.shields.io/npm/v/@dash-ui/react?style=for-the-badge&labelColor=24292e">
</a>
<a aria-label="License" href="https://jaredlunde.mit-license.org/">
<img alt="MIT License" src="https://img.shields.io/npm/l/@dash-ui/react?style=for-the-badge&labelColor=24292e">
</a>
<hr>
## Quick Start
> NOTE: You do not need to use this package to use `@dash-ui` with React. This merely
> provides a few useful utilities, particularly on the server-side.
[Check out an example on **CodeSandbox**](https://codesandbox.io/s/dash-uireact-example-tkly3?file=/src/App.tsx)
```jsx harmony
import { createStyles } from "@dash-ui/styles";
import { useGlobal } from "@dash-ui/react";
const styles = createStyles({
tokens: {
color: {
primary: "#ee5b5f",
},
},
});
const Heading = () => {
useGlobal(
styles,
({ color }) => `
h1 {
font-size: 2rem;
font-family: -apple-system, sans-serif;
color: ${color.primary};
}
`,
[]
);
return <h1>Hello world</h1>;
};
```
## API docs
### Components
| Component | Description |
| --------------------- | ----------------------------------------------------------------------------------------------- |
| [`<Inline>`](#inline) | A component for creating an inline `<style>` tag that is unmounted when the component unmounts. |
### Hooks
| Hook | Description |
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`useCSS()`](#usecss) | A hook for [performantly and reliably](https://github.com/reactwg/react-18/discussions/110) inserting CSS into the DOM in React 18 using the `useInsertionEffect` hook. |
| [`useGlobal()`](#useglobal) | A hook for inserting transient global styles into the DOM. These styles will be injected when the hook mounts and flushed when the hook unmounts. |
| [`useTokens()`](#usetokens) | A hook for inserting transient CSS tokens into the DOM. These tokens will be injected when the hook mounts and flushed when the hook unmounts. |
| [`useThemes()`](#usethemes) | A hook for inserting transient CSS theme tokens into the DOM. These tokens will be injected when the hook mounts and flushed when the hook unmounts. |
### Server rendering
| | Description |
| ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`<Style>`](#style) | A React component for injecting SSR CSS styles into Next.js documents. |
| [`toComponent()`](#tocomponent) | A function for creating a React `<style>` component for inserting Dash styles in SSR. |
| [`createGatsbyRenderer`](#creategatsbyrenderer) | Creates a Gatsby [replaceRenderer](https://www.gatsbyjs.org/docs/ssr-apis/#replaceRenderer) for injecting styles generated by Dash on the server into the Gatsby `<head>` component |
### TypeScript support
Dash is written in TypeScript. It's also strongly typed, creating a beautiful IntelliSense
experience in VSCode and providing solid insurance to your TypeScript application.
| | Description |
| ----------------------------------------------- | -------------------------------------------------------------------------- |
| [Strongly typed tokens](#strongly-typed-tokens) | Learn how to add autocomplete and type safety to your CSS tokens. |
| [Strongly typed themes](#strongly-typed-tokens) | Learn how to add autocomplete and type safety to your CSS variable themes. |
### <Inline>
A component for creating an inline `<style>` tag that is unmounted when the component unmounts.
#### Example
[Play with an example on **CodeSandbox**](https://codesandbox.io/s/dash-uireact-inline-example-d4nf9?file=/src/App.tsx)
```tsx
import * as React from 'react'
import {styles} from '@dash-ui/styles'
import {Inline} from '@dash-ui/react'
export const App = () => {
return (
<React.Fragment>
<Inline styles={styles} css={`
.heading {
font-size: 2rem;
font-family: -apple-system, sans-serif;
}
`}>
<h1 className='heading'>Hello world</h1>
</React.Fragment>
)
}
```
#### Props
| Prop | Type | Required? | Description |
| ------ | -------------------------------- | --------- | -------------------------------------- |
| styles | `Styles<DashTokens, DashThemes>` | Yes | A `styles` instance. |
| css | `StyleValue<DashTokens>` | Yes | The CSS you want to inline in the DOM. |
### useCSS()
A hook for [performantly and reliably](https://github.com/reactwg/react-18/discussions/110) inserting CSS into the DOM in React 18 using the
`useInsertionEffect` hook.
#### Example
[Play with an example on **CodeSandbox**](https://codesandbox.io/s/dash-ui-react-usecss-example-gi3o6o)
```tsx
import * as React from "react";
import { createStyles } from "@dash-ui/styles";
import { useGlobal } from "@dash-ui/react";
const styles = createStyles();
const Component = () => {
const classes = useCSS(styles, {
root: styles.one({ display: "flex", gap: "2rem" }),
});
return (
<div className={classes.root}>
<div>Hello</div>
<div>World</div>
</div>
);
};
```
#### Returns
```typescript
Record<ClassNames, string>;
```
### useGlobal()
A hook for inserting transient global styles into the DOM. These styles will be
injected when the hook mounts and flushed when the hook unmounts.
#### Example
[Play with an example on **CodeSandbox**](https://codesandbox.io/s/dash-uireact-useglobal-example-u0urr?file=/src/App.tsx)
```tsx
import * as React from "react";
import { createStyles } from "@dash-ui/styles";
import { useGlobal } from "@dash-ui/react";
const styles = createStyles();
const Component = () => {
useGlobal(
styles,
{
body: {
minHeight: "100vh",
backgroundColor: "#ee5b5f",
color: "#fff",
fontFamily: "Inter, -apple-system, sans-serif",
},
h1: {
margin: "1rem",
fontSize: "3rem",
},
},
[]
);
return (
<div>
<h1>Hello world</h1>
</div>
);
};
```
#### Returns
```typescript
null;
```
### useTokens()
A hook for inserting transient CSS tokens into the DOM. These tokens will be
injected when the hook mounts and flushed when the hook unmounts.
#### Example
[Play with an example on **CodeSandbox**](https://codesandbox.io/s/dash-uireact-usetokens-example-uwegk?file=/src/App.tsx)
```tsx
import * as React from "react";
import { createStyles } from "@dash-ui/styles";
import { useThemes } from "@dash-ui/react";
const styles = createStyles({
tokens: {
primaryColor: "#ee5b5f",
},
});
const Component = () => {
const [primaryColor, setPrimaryColor] = React.useState("#ee5b5f");
useTokens(styles, { primaryColor }, [primaryColor]);
return (
<div>
<div
className={styles.cls(
({ primaryColor }) => `
width: 200px;
height: 200px;
background-color: ${primaryColor};
`
)}
/>
<label>
<h4>Primary color</h4>
<input
value={primaryColor}
onChange={(e) => setPrimaryColor(e.target.value)}
/>
</label>
</div>
);
};
```
#### Arguments
```typescript
function useTokens(
value: PartialDeep<DashTokens> | Falsy,
deps?: React.DependencyList
);
```
| Argument | Type | Required? | Description |
| -------- | -------------------------------- | --------- | --------------------------------------------------------------- | ------------------------------------------------------------------ |
| styles | `Styles<DashTokens, DashThemes>` | Yes | A `styles` instance. |
| value | `PartialDeep<DashTokens> | Falsy` | Yes | CSS tokens to inject into the DOM and flush when the hook unmounts |
| deps | `React.DependencyList` | No | A dependency array that will force the hook to re-insert tokens |
#### Returns
```typescript
null;
```
### useThemes()
A hook for inserting transient CSS theme tokens into the DOM. These tokens
will be injected when the hook mounts and flushed when the hook unmounts.
#### Example
[Play with an example on **CodeSandbox**](https://codesandbox.io/s/dash-uireact-usethemes-example-cdb0d?file=/src/App.tsx)
```jsx
import * as React from "react";
import { createStyles } from "@dash-ui/styles";
import { useThemes } from "@dash-ui/react";
const styles = createStyles({
themes: {
// Light mode CSS tokens
light: {
primaryColor: "#ee5b5f",
},
// Dark mode CSS tokens
dark: {
primaryColor: "#272727",
},
},
});
const Component = () => {
const [mode, setMode] = React.useState("light");
const [darkModePrimary, setDarkModePrimary] = React.useState("#272727");
const [lightModePrimary, setLightModePrimary] = React.useState("#ee5b5f");
useThemes(
{
light: {
primaryColor: lightModePrimary,
},
dark: {
primaryColor: darkModePrimary,
},
},
[darkModePrimary, lightModePrimary]
);
return (
<body className={styles.theme(mode)}>
<div
className={styles.cls(
({ primaryColor }) => `
width: 200px;
height: 200px;
background-color: ${primaryColor};
`
)}
/>
<div>
<button
onClick={() =>
setMode((mode) => (mode === "light" ? "dark" : "light"))
}
>
Switch to {mode === "light" ? "dark" : "light"} mode
</button>
</div>
<label>
<h4>Light mode primary color</h4>
<input
value={lightModePrimary}
onChange={(e) => setLightModePrimary(e.target.value)}
/>
</label>
<label>
<h4>Dark mode primary color</h4>
<input
value={darkModePrimary}
onChange={(e) => setDarkModePrimary(e.target.value)}
/>
</label>
</body>
);
};
```
#### Arguments
```typescript
function useThemes(
styles,
value: PartialDeep<DashThemes> | Falsy,
deps?: React.DependencyList
);
```
| Argument | Type | Required? | Description |
| -------- | --------------------------------- | --------- | --------------------------------------------------------------- |
| styles | `Styles<DashTokens, DashThemes>` | Yes | A `styles` instance. |
| value | `PartialDeep<DashThemes>\| Falsy` | Yes | Themes to inject into the DOM and flush when the hook unmounts |
| deps | `React.DependencyList` | No | A dependency array that will force the hook to re-insert themes |
#### Returns
```typescript
null;
```
### <Style>
A React component for injecting SSR CSS styles into Next.js documents.
#### Example
```tsx
// _document.js
import React from "react";
import Document from "next/document";
import { styles } from "@dash-ui/styles";
import { Style } from "@dash-ui/react/server";
export default class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx);
return {
...initialProps,
styles: (
<React.Fragment>
{initialProps.styles}
<Style html={initialProps.html} styles={styles} />
</React.Fragment>
),
};
}
}
```
#### Props
| Prop | Type | Required? | Description |
| ------ | -------------------------------- | --------- | -------------------------------------------------------------------------------------- |
| html | `string` | Yes | HTML generated by Next.js, `renderToStaticMarkup()` or `renderToString()` |
| styles | `Styles<DashTokens, DashThemes>` | No | An instance of `styles`. Defaults to the default styles instance in `@dash-ui/styles`. |
### toComponent()
A function for creating a React `<style>` component for inserting Dash styles in SSR.
#### Example
```tsx
// _document.js
import React from "react";
import Document from "next/document";
import { styles } from "@dash-ui/styles";
import { toComponent } from "@dash-ui/react/server";
export default class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx);
return {
...initialProps,
styles: (
<React.Fragment>
{initialProps.styles}
{toComponent(initialProps.html, styles)}
</React.Fragment>
),
};
}
}
```
#### Arguments
```typescript
function toComponent(
html: string,
styles: Styles = defaultStyles
): React.ReactElement;
```
| Argument | Type | Required? | Description |
| -------- | -------------------------------- | --------- | -------------------------------------------------------------------------------------- |
| html | `string` | Yes | The HTML generated by `renderToStaticMarkup()` or `renderToString()` |
| styles | `Styles<DashTokens, DashThemes>` | No | An instance of `styles`. Defaults to the default styles instance in `@dash-ui/styles`. |
#### Returns
```typescript
React.ReactElement; // A <style> element
```
### createGatsbyRenderer()
Creates a Gatsby [replaceRenderer](https://www.gatsbyjs.org/docs/ssr-apis/#replaceRenderer) for
injecting styles generated by Dash on the server into the Gatsby `<head>` component.
#### Example
```js
// gatsby-ssr.js
const { styles } = require("@dash-ui/styles");
exports.replaceRenderer =
require("@dash-ui/react/server").createGatsbyRenderer(styles);
```
#### Arguments
```typescript
function createGatsbyRenderer(styles: Styles = defaultStyles);
```
| Argument | Type | Required? | Description |
| -------- | -------------------------------- | --------- | -------------------------------------------------------------------------------------- |
| styles | `Styles<DashTokens, DashThemes>` | Yes | An instance of `styles`. Defaults to the default styles instance in `@dash-ui/styles`. |
#### Returns
```typescript
function replaceRenderer<P = any>(props: P): P; // A Gatsby replace renderer
```
## Strongly typed tokens
To use variable types with `@dash-ui/react`, you have to use the module declaration
pattern:
[Play with this example on **CodeSandbox**](https://codesandbox.io/s/dash-uistyles-strongly-typed-tokens-example-2-yk9bc?file=/src/App.tsx)
```typescript
const tokens = {
color: {
red: "#c17",
},
};
type AppTokens = typeof tokens;
declare module "@dash-ui/styles" {
export interface DashTokens extends AppTokens {}
}
// OR alternatively
declare module "@dash-ui/styles" {
export interface DashTokens {
color: {
red: string;
};
}
}
```
## Strongly typed themes
To use variable/theme types with `@dash-ui/react`, you have to use the module declaration
pattern:
[Play with the example on **CodeSandbox**](https://codesandbox.io/s/dash-uistyles-strongly-typed-themes-example-2-64me1?file=/src/App.tsx)
```typescript
const themes = {
light: {
color: {
// var(--color-bg)
bg: "#fafafa",
},
},
dark: {
color: {
// var(--color-bg)
bg: "#1a1a1a",
},
},
};
type AppThemes = typeof themes;
type AppTokens = AppThemes["dark"] & AppThemes["light"];
declare module "@dash-ui/styles" {
export interface DashTokens extends AppTokens {}
export interface DashThemes extends AppThemes {}
}
// OR alternatively
declare module "@dash-ui/styles" {
export interface DashTokens {
color: {
bg: string;
};
}
export interface DashThemes {
light: DashTokens;
dark: DashTokens;
}
}
```
## LICENSE
MIT