diff --git a/css-hooks/.eslintrc.js b/css-hooks/.eslintrc.js
new file mode 100644
index 000000000..2061cd226
--- /dev/null
+++ b/css-hooks/.eslintrc.js
@@ -0,0 +1,4 @@
+/** @type {import('eslint').Linter.Config} */
+module.exports = {
+ extends: ["@remix-run/eslint-config", "@remix-run/eslint-config/node"],
+};
diff --git a/css-hooks/.gitignore b/css-hooks/.gitignore
new file mode 100644
index 000000000..3f7bf98da
--- /dev/null
+++ b/css-hooks/.gitignore
@@ -0,0 +1,6 @@
+node_modules
+
+/.cache
+/build
+/public/build
+.env
diff --git a/css-hooks/README.md b/css-hooks/README.md
new file mode 100644
index 000000000..5437f8156
--- /dev/null
+++ b/css-hooks/README.md
@@ -0,0 +1,19 @@
+# CSS Hooks
+
+Hooks bring CSS features to native inline styles, enabling you to target various states such as `:hover`, `:focus`, and `:active`, all without leaving the `style` prop.
+
+## Preview
+
+Open this example on [CodeSandbox](https://codesandbox.com):
+
+[![Open in CodeSandbox](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/remix-run/examples/tree/main/css-hooks)
+
+## Example
+
+This quick example shows how CSS Hooks can be used to apply `:hover` and `:active` styles on links.
+
+## Related Links
+
+- [Website](https://css-hooks.com)
+- [Getting started](https://css-hooks.com/docs/react/getting-started)
+- [Explanation: _From CSS madness to CSS Hooks_](https://nsaunders.dev/posts/css-madness-to-hooks)
\ No newline at end of file
diff --git a/css-hooks/app/css-hooks.ts b/css-hooks/app/css-hooks.ts
new file mode 100644
index 000000000..a9887ee0d
--- /dev/null
+++ b/css-hooks/app/css-hooks.ts
@@ -0,0 +1,6 @@
+import { createHooks, recommended } from "@css-hooks/react";
+
+const [css, hooks] = createHooks(recommended);
+
+export default hooks;
+export { css }
diff --git a/css-hooks/app/root.tsx b/css-hooks/app/root.tsx
new file mode 100644
index 000000000..d76eaa801
--- /dev/null
+++ b/css-hooks/app/root.tsx
@@ -0,0 +1,34 @@
+import type { MetaFunction } from "@remix-run/node";
+import {
+ Links,
+ LiveReload,
+ Meta,
+ Outlet,
+ Scripts,
+ ScrollRestoration,
+} from "@remix-run/react";
+import { css } from "./css-hooks";
+
+export const meta: MetaFunction = () => ({
+ charset: "utf-8",
+ title: "Remix with CSS Hooks",
+ viewport: "width=device-width,initial-scale=1",
+});
+
+export default function App() {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/css-hooks/app/routes/_index.tsx b/css-hooks/app/routes/_index.tsx
new file mode 100644
index 000000000..8ea119956
--- /dev/null
+++ b/css-hooks/app/routes/_index.tsx
@@ -0,0 +1,42 @@
+import { ComponentPropsWithoutRef } from "react";
+import hooks from "../css-hooks";
+
+function A(props: Omit, "style">) {
+ return (
+
+ );
+}
+
+export default function Index() {
+ return (
+
+ );
+}
diff --git a/css-hooks/package.json b/css-hooks/package.json
new file mode 100644
index 000000000..156cf174e
--- /dev/null
+++ b/css-hooks/package.json
@@ -0,0 +1,30 @@
+{
+ "private": true,
+ "sideEffects": false,
+ "scripts": {
+ "build": "remix build",
+ "dev": "remix dev",
+ "start": "remix-serve build",
+ "typecheck": "tsc"
+ },
+ "dependencies": {
+ "@css-hooks/react": "^1.2.1",
+ "@remix-run/node": "^1.19.3",
+ "@remix-run/react": "^1.19.3",
+ "@remix-run/serve": "^1.19.3",
+ "isbot": "^3.6.5",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0"
+ },
+ "devDependencies": {
+ "@remix-run/dev": "^1.19.3",
+ "@remix-run/eslint-config": "^1.19.3",
+ "@types/react": "^18.0.25",
+ "@types/react-dom": "^18.0.8",
+ "eslint": "^8.27.0",
+ "typescript": "^4.8.4"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+}
diff --git a/css-hooks/public/favicon.ico b/css-hooks/public/favicon.ico
new file mode 100644
index 000000000..8830cf682
Binary files /dev/null and b/css-hooks/public/favicon.ico differ
diff --git a/css-hooks/remix.config.js b/css-hooks/remix.config.js
new file mode 100644
index 000000000..ca00ba946
--- /dev/null
+++ b/css-hooks/remix.config.js
@@ -0,0 +1,11 @@
+/** @type {import('@remix-run/dev').AppConfig} */
+module.exports = {
+ future: {
+ v2_routeConvention: true,
+ },
+ ignoredRouteFiles: ["**/.*"],
+ // appDirectory: "app",
+ // assetsBuildDirectory: "public/build",
+ // publicPath: "/build/",
+ // serverBuildPath: "build/index.js",
+};
diff --git a/css-hooks/remix.env.d.ts b/css-hooks/remix.env.d.ts
new file mode 100644
index 000000000..dcf8c45e1
--- /dev/null
+++ b/css-hooks/remix.env.d.ts
@@ -0,0 +1,2 @@
+///
+///
diff --git a/css-hooks/sandbox.config.json b/css-hooks/sandbox.config.json
new file mode 100644
index 000000000..f92e0250c
--- /dev/null
+++ b/css-hooks/sandbox.config.json
@@ -0,0 +1,7 @@
+{
+ "hardReloadOnChange": true,
+ "template": "remix",
+ "container": {
+ "port": 3000
+ }
+}
diff --git a/css-hooks/tsconfig.json b/css-hooks/tsconfig.json
new file mode 100644
index 000000000..20f8a386a
--- /dev/null
+++ b/css-hooks/tsconfig.json
@@ -0,0 +1,22 @@
+{
+ "include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"],
+ "compilerOptions": {
+ "lib": ["DOM", "DOM.Iterable", "ES2019"],
+ "isolatedModules": true,
+ "esModuleInterop": true,
+ "jsx": "react-jsx",
+ "moduleResolution": "node",
+ "resolveJsonModule": true,
+ "target": "ES2019",
+ "strict": true,
+ "allowJs": true,
+ "forceConsistentCasingInFileNames": true,
+ "baseUrl": ".",
+ "paths": {
+ "~/*": ["./app/*"]
+ },
+
+ // Remix takes care of building everything in `remix build`.
+ "noEmit": true
+ }
+}