// TW 3
@layer components {
.x {
color: red;
border: 1px solid red;
}
}
// TW 4
@utility x {
color: red;
border: 1px solid red;
}
<div class="[&_ul]:x">
<ul>
<li>Test</li>
</ul>
</div>
import { useState, useMemo } from "react"
import { checkEmail, checkPassword } from "./validators"
export function StateForm() {
const [email, setEmail] = useState("")
const [password, setPassword] = useState("")
const [isAfterFirstSubmit, setIsAfterFirstSubmit] = useState(false)
const emailErrors = useMemo(() => {
return isAfterFirstSubmit ? checkEmail(email) : []
}, [isAfterFirstSubmit, email])
const passwordErrors = useMemo(() => {
return isAfterFirstSubmit ? checkPassword(password) : []
}, [isAfterFirstSubmit, password])
function onSubmit(e) {
e.preventDefault()
setIsAfterFirstSubmit(true)
const emailResults = checkEmail(email)
const passwordResults = checkPassword(password)
if (emailResults.length === 0 && passwordResults.length === 0) {
alert("Success")
}
}
return (
<form onSubmit={onSubmit} className="form">
<div className={`form-group ${emailErrors.length > 0 ? "error" : ""}`}>
<label className="label" htmlFor="email">
Email
</label>
<input
className="input"
type="email"
id="email"
value={email}
onChange={e => setEmail(e.target.value)}
/>
{emailErrors.length > 0 && (
<div className="msg">{emailErrors.join(", ")}</div>
)}
</div>
<div className={`form-group ${passwordErrors.length > 0 ? "error" : ""}`}>
<label className="label" htmlFor="password">
Password
</label>
<input
className="input"
type="password"
id="password"
value={password}
onChange={e => setPassword(e.target.value)}
/>
{passwordErrors.length > 0 && (
<div className="msg">{passwordErrors.join(", ")}</div>
)}
</div>
<button className="btn" type="submit">
Submit
</button>
</form>
)
}
import { useEffect, useState } from "react"
export function useLocalStorage(key, initialValue) {
const [value, setValue] = useState(() => {
const localValue = localStorage.getItem(key)
if (localValue == null) {
if (typeof initialValue === "function") {
return initialValue()
} else {
return initialValue
}
} else {
return JSON.parse(localValue)
}
})
useEffect(() => {
if (value === undefined) {
localStorage.removeItem(key)
} else {
localStorage.setItem(key, JSON.stringify(value))
}
}, [value, key])
return [value, setValue]
}
import { useState, useCallback } from "react"
export function useArray(initialValue) {
const [array, setArray] = useState(initialValue)
const push = useCallback(element => {
setArray(a => [...a, element])
}, [])
const replace = useCallback((index, newElement) => {
setArray(a => {
return [...a.slice(0, index), newElement, ...a.slice(index + 1)]
})
}, [])
const filter = useCallback(callback => {
setArray(a => {
return a.filter(callback)
})
}, [])
const remove = useCallback(index => {
setArray(a => {
return [...a.slice(0, index), ...a.slice(index + 1)]
})
}, [])
const clear = useCallback(() => {
setArray([])
}, [])
const reset = useCallback(() => {
setArray(initialValue)
}, [initialValue])
return { array, set: setArray, push, replace, filter, remove, clear, reset }
}
import { useEffect, useState } from "react"
import { User } from "./User"
export default function App() {
const [users, setUsers] = useState([])
const [error, setError] = useState(null)
const [status, setStatus] = useState("idle")
useEffect(() => {
setStatus("loading")
setUsers([])
setError(null)
const controller = new AbortController()
fetch("https://jsonplaceholder.typicode.com/users", {
signal: controller.signal,
})
.then(res => {
if (res.ok) return res.json()
throw new Error(`Status code: ${res.status}`)
})
.then(data => {
setUsers(data)
setStatus("fetched")
setError(null)
})
.catch(err => {
if (err.name === "AbortError") return
setError(err)
setUsers([])
setStatus("error")
})
return () => {
controller.abort()
}
}, [])
return (
<>
<h1>User List</h1>
{status === "loading" && <h2>Loading...</h2>}
{status === "error" && (
<>
<h2>Error fetching users</h2>
<p>{error.message}</p>
</>
)}
{status === "fetched" && (
<ul>
{users.map(user => (
<User key={user.id} name={user.name} />
))}
</ul>
)}
</>
)
}
import { useState, useEffect } from 'react';
const useFetch = (url) => {
const [data, setData] = useState(null);
const [isPending, setIsPending] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
setTimeout(() => {
fetch(url)
.then(res => {
if (!res.ok) { // error coming back from server
throw Error('could not fetch the data for that resource');
}
return res.json();
})
.then(data => {
setIsPending(false);
setData(data);
setError(null);
})
.catch(err => {
// auto catches network / connection error
setIsPending(false);
setError(err.message);
})
}, 1000);
}, [url])
return { data, isPending, error };
}
export default useFetch;
import { useState } from "react";
function Cart() {
const [cart, setCart] = useState({
items: [],
total: 0,
discount: null,
isLoading: false,
});
const addItem = (item) =>
setCart(prev => ({
...prev,
items: [...prev.items, item],
total: prev.total + item.price,
}));
const removeItem = (id) =>
setCart(prev => {
const item = prev.items.find(i => i.id === id);
return {
...prev,
items: prev.items.filter(i => i.id !== id),
total: prev.total - (item?.price || 0),
};
});
const applyDiscount = (code) =>
setCart(prev => ({ ...prev, discount: code }));
const resetCart = () =>
setCart({ items: [], total: 0, discount: null, isLoading: false });
return <div>{JSON.stringify(cart)}</div>;
}
<!DOCTYPE html>
<html lang="cs">
<head>
<meta charset="UTF-8">
<title>CSS Anchor Positioning Demo 2026</title>
<style>
/* Pomocný styling pro demo */
body {
margin: 0;
font-family: sans-serif;
}
section {
height: 100vh;
background: orange;
display: flex;
align-items: center;
justify-content: center;
font-size: 2rem;
color: white;
}
ul {
padding: 50px;
background: #eee;
}
/* DEFINICE KOTVY (Anchor) */
li {
anchor-name: --li;
border: 2px solid black;
min-height: 300px;
list-style: none;
display: flex;
align-items: center;
justify-content: center;
background: white;
/* POZOR: Nesmí zde být position: relative, jinak span kotvu neuvidí */
}
/* DEFINICE POZICOVANÉHO PRVKU (Target) */
span {
all: unset; /* Vyčištění výchozích stylů */
display: block;
background: pink;
width: fit-content;
padding: 1rem;
border-radius: 8px;
box-shadow: 0 4px 10px rgba(0,0,0,0.2);
font-weight: bold;
/* Propojení s kotvou */
position: fixed; /* Vztahuje se k viewportu (nutné pro flip) */
position-anchor: --li; /* Jméno kotvy */
/* Výchozí pozice: NAHOŘE */
position-area: top;
/* AUTOMATICKÉ PŘEKLOPENÍ */
/* flip-block automaticky změní 'top' na 'bottom', když nahoře dojde místo */
position-try-fallbacks: flip-block;
/* Volitelné: Plynulý přechod pozice (podporováno od Chrome 129+) [1, 2] */
transition: position-area 0.3s;
}
/* Ukázka, jak by vypadalo ruční přepsání přes @position-try,
pokud byste nepoužil flip-block:
@position-try --dolu {
position-area: bottom;
margin-top: 10px;
}
*/
</style>
</head>
<body>
<section>Scrollujte dolů k růžovému tooltipu...</section>
<ul>
<li>
<div>AAA (Kotva)</div>
<span>BBB (Tooltip - přeskakuje nahoru/dolů)</span>
</li>
</ul>
<section>Scrollujte zpět nahoru...</section>
</body>
</html>