Quickstart: No framework
1 Initialize project
npm create vite@latest css-hooks-playground -- --template vanilla-ts
cd css-hooks-playground
npm install @css-hooks/core remeda
2 Start dev server
npm run dev
Visit http://localhost:5173 to view changes in real time.
3 Set up CSS Hooks
Create a src/css.ts
module with the following contents:
import { buildHooksSystem } from "@css-hooks/core";
const createHooks = buildHooksSystem();
export const { styleSheet, on } = createHooks("&:active");
/**
* Converts a style object to a string.
*
* @remarks
* This functionality (or equivalent) would typically be bundled with an app framework.
*/
export function styleObjectToString(obj: Record<string, unknown>) {
return Object.entries(obj)
.filter(
([, value]) => typeof value === "string" || typeof value === "number",
)
.map(
([property, value]) =>
`${/^--/.test(property) ? property : property.replace(/[A-Z]/g, x => `-${x.toLowerCase()}`)}: ${value}`,
)
.join("; ");
}
4 Add style sheet
Modify src/main.ts
to add the style sheet to the document:
import './style.css'
import typescriptLogo from './typescript.svg'
import viteLogo from '/vite.svg'
import { setupCounter } from './counter.ts'
import { styleSheet } from './css.ts'
document.querySelector<HTMLDivElement>('#app')!.innerHTML = `
<style>${styleSheet()}</style>
<div>
<a href="https://vitejs.dev" target="_blank">
<img src="${viteLogo}" class="logo" alt="Vite logo" />
</a>
<a href="https://www.typescriptlang.org/" target="_blank">
<img src="${typescriptLogo}" class="logo vanilla" alt="TypeScript logo" />
</a>
<h1>Vite + TypeScript</h1>
<div class="card">
<button id="counter" type="button"></button>
</div>
<p class="read-the-docs">
Click on the Vite and TypeScript logos to learn more
</p>
</div>
`
setupCounter(document.querySelector<HTMLButtonElement>('#counter')!)
5 Add conditional style
Use the configured &:active
hook to implement an effect when the counter
button is pressed:
// src/main.ts
import './style.css'
import typescriptLogo from './typescript.svg'
import viteLogo from '/vite.svg'
import { setupCounter } from './counter.ts'
import { styleSheet } from './css.ts'
import { on, styleObjectToString, styleSheet } from './css.ts'
import { pipe } from 'remeda'
document.querySelector<HTMLDivElement>('#app')!.innerHTML = `
<style>${styleSheet()}</style>
<div>
<a href="https://vitejs.dev" target="_blank">
<img src="${viteLogo}" class="logo" alt="Vite logo" />
</a>
<a href="https://www.typescriptlang.org/" target="_blank">
<img src="${typescriptLogo}" class="logo vanilla" alt="TypeScript logo" />
</a>
<h1>Vite + TypeScript</h1>
<div class="card">
<button id="counter" type="button"></button>
<button
id="counter"
type="button"
style="${styleObjectToString(
pipe(
{
transition: 'transform 75ms',
},
on('&:active', {
transform: 'scale(0.9)'
})
)
)}">
</button>
</div>
<p class="read-the-docs">
Click on the Vite and TypeScript logos to learn more
</p>
</div>
`
setupCounter(document.querySelector<HTMLButtonElement>('#counter')!)