or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

animations.mdconfiguration.mdcss-classes.mdglobal-styles.mdindex.mdstyled-components.mdtheme-management.md

animations.mddocs/

0

# Animations

1

2

Create CSS animations with keyframes and integrate with theme tokens. The `keyframes` function generates CSS animations that can be used across styled components and CSS classes.

3

4

## Capabilities

5

6

### Keyframes Function

7

8

Creates CSS keyframe animations that can be referenced in styles.

9

10

```typescript { .api }

11

/**

12

* Creates CSS keyframe animations

13

* @param styles - Object defining animation keyframes with percentages or keywords

14

* @returns Keyframes object with name property and toString method

15

*/

16

function keyframes(styles: KeyframesObject): KeyframesResult;

17

18

interface KeyframesObject {

19

/** Keyframe percentages (0%, 50%, 100%) or keywords (from, to) */

20

[percentage: string]: StyleObject;

21

}

22

23

interface KeyframesResult {

24

/** Returns the animation name for use in CSS */

25

(): string;

26

/** CSS animation name */

27

name: string;

28

/** String representation of the animation name */

29

toString(): string;

30

}

31

```

32

33

**Usage Examples:**

34

35

```typescript

36

import { keyframes, styled } from "@stitches/react";

37

38

// Basic fade in animation

39

const fadeIn = keyframes({

40

'0%': { opacity: 0 },

41

'100%': { opacity: 1 }

42

});

43

44

// Complex animation with multiple keyframes

45

const slideAndScale = keyframes({

46

'0%': {

47

transform: 'translateX(-100px) scale(0.8)',

48

opacity: 0

49

},

50

'50%': {

51

transform: 'translateX(0) scale(1.1)',

52

opacity: 0.8

53

},

54

'100%': {

55

transform: 'translateX(0) scale(1)',

56

opacity: 1

57

}

58

});

59

60

// Use in styled components

61

const AnimatedBox = styled('div', {

62

animation: `${fadeIn} 0.3s ease-out`

63

});

64

65

const ComplexAnimatedBox = styled('div', {

66

animation: `${slideAndScale} 0.6s ease-out`

67

});

68

```

69

70

### Animation with Variants

71

72

Combine animations with variant systems for conditional animations.

73

74

**Usage Examples:**

75

76

```typescript

77

const bounce = keyframes({

78

'0%, 20%, 53%, 80%, 100%': {

79

transform: 'translate3d(0, 0, 0)'

80

},

81

'40%, 43%': {

82

transform: 'translate3d(0, -30px, 0)'

83

},

84

'70%': {

85

transform: 'translate3d(0, -15px, 0)'

86

},

87

'90%': {

88

transform: 'translate3d(0, -4px, 0)'

89

}

90

});

91

92

const pulse = keyframes({

93

'0%': {

94

transform: 'scale(1)'

95

},

96

'50%': {

97

transform: 'scale(1.05)'

98

},

99

'100%': {

100

transform: 'scale(1)'

101

}

102

});

103

104

const AnimatedButton = styled('button', {

105

padding: '12px 24px',

106

border: 'none',

107

borderRadius: '4px',

108

cursor: 'pointer',

109

110

variants: {

111

animation: {

112

none: {},

113

bounce: {

114

animation: `${bounce} 1s ease-in-out`

115

},

116

pulse: {

117

animation: `${pulse} 2s infinite`

118

},

119

fadeIn: {

120

animation: `${fadeIn} 0.3s ease-out`

121

}

122

},

123

loading: {

124

true: {

125

animation: `${pulse} 1s infinite`

126

}

127

}

128

}

129

});

130

131

// Usage with animation variants

132

<AnimatedButton animation="bounce">Bouncy Button</AnimatedButton>

133

<AnimatedButton loading={true}>Loading Button</AnimatedButton>

134

```

135

136

### Theme Token Integration

137

138

Use theme tokens within keyframe animations.

139

140

**Usage Examples:**

141

142

```typescript

143

import { createTheme, keyframes, styled } from "@stitches/react";

144

145

const theme = createTheme({

146

colors: {

147

primary: 'blue',

148

secondary: 'lightblue'

149

},

150

space: {

151

sm: '8px',

152

md: '16px',

153

lg: '24px'

154

}

155

});

156

157

// Animations using theme tokens

158

const colorShift = keyframes({

159

'0%': {

160

backgroundColor: '$colors$primary',

161

transform: 'translateY(0)'

162

},

163

'50%': {

164

backgroundColor: '$colors$secondary',

165

transform: 'translateY(-$space$md)'

166

},

167

'100%': {

168

backgroundColor: '$colors$primary',

169

transform: 'translateY(0)'

170

}

171

});

172

173

const ThemeAnimatedBox = styled('div', {

174

width: '100px',

175

height: '100px',

176

animation: `${colorShift} 2s infinite ease-in-out`

177

});

178

```

179

180

### Complex Animations

181

182

Create sophisticated multi-step animations with precise timing.

183

184

**Usage Examples:**

185

186

```typescript

187

// Loading spinner animation

188

const spin = keyframes({

189

'0%': { transform: 'rotate(0deg)' },

190

'100%': { transform: 'rotate(360deg)' }

191

});

192

193

// Morphing animation

194

const morphing = keyframes({

195

'0%': {

196

borderRadius: '50%',

197

transform: 'scale(1) rotate(0deg)'

198

},

199

'25%': {

200

borderRadius: '25%',

201

transform: 'scale(1.2) rotate(90deg)'

202

},

203

'50%': {

204

borderRadius: '0%',

205

transform: 'scale(1.4) rotate(180deg)'

206

},

207

'75%': {

208

borderRadius: '25%',

209

transform: 'scale(1.2) rotate(270deg)'

210

},

211

'100%': {

212

borderRadius: '50%',

213

transform: 'scale(1) rotate(360deg)'

214

}

215

});

216

217

// Typing animation

218

const typing = keyframes({

219

'from': { width: '0' },

220

'to': { width: '100%' }

221

});

222

223

const blink = keyframes({

224

'0%, 50%': { borderColor: 'transparent' },

225

'51%, 100%': { borderColor: 'currentColor' }

226

});

227

228

const Spinner = styled('div', {

229

width: '20px',

230

height: '20px',

231

border: '2px solid transparent',

232

borderTop: '2px solid currentColor',

233

borderRadius: '50%',

234

animation: `${spin} 1s linear infinite`

235

});

236

237

const MorphingBox = styled('div', {

238

width: '50px',

239

height: '50px',

240

backgroundColor: 'blue',

241

animation: `${morphing} 3s infinite ease-in-out`

242

});

243

244

const TypingText = styled('div', {

245

overflow: 'hidden',

246

borderRight: '2px solid currentColor',

247

whiteSpace: 'nowrap',

248

animation: `

249

${typing} 3s steps(40, end),

250

${blink} 0.75s step-end infinite

251

`

252

});

253

```

254

255

### Animation States and Controls

256

257

Control animations based on component state and user interactions.

258

259

**Usage Examples:**

260

261

```typescript

262

const slideInLeft = keyframes({

263

from: { transform: 'translateX(-100%)' },

264

to: { transform: 'translateX(0)' }

265

});

266

267

const slideInRight = keyframes({

268

from: { transform: 'translateX(100%)' },

269

to: { transform: 'translateX(0)' }

270

});

271

272

const scaleUp = keyframes({

273

from: { transform: 'scale(0.5)', opacity: 0 },

274

to: { transform: 'scale(1)', opacity: 1 }

275

});

276

277

const InteractiveCard = styled('div', {

278

padding: '20px',

279

backgroundColor: 'white',

280

borderRadius: '8px',

281

boxShadow: '0 2px 4px rgba(0,0,0,0.1)',

282

transition: 'transform 0.2s ease',

283

284

variants: {

285

entrance: {

286

slideLeft: {

287

animation: `${slideInLeft} 0.5s ease-out`

288

},

289

slideRight: {

290

animation: `${slideInRight} 0.5s ease-out`

291

},

292

scale: {

293

animation: `${scaleUp} 0.3s ease-out`

294

}

295

},

296

hover: {

297

true: {

298

'&:hover': {

299

transform: 'translateY(-4px)'

300

}

301

}

302

}

303

}

304

});

305

306

// Usage with different entrance animations

307

<InteractiveCard entrance="slideLeft" hover>

308

Slides in from left

309

</InteractiveCard>

310

```

311

312

### Animation Composition

313

314

Combine multiple animations for complex effects.

315

316

**Usage Examples:**

317

318

```typescript

319

const float = keyframes({

320

'0%, 100%': { transform: 'translateY(0px)' },

321

'50%': { transform: 'translateY(-10px)' }

322

});

323

324

const glow = keyframes({

325

'0%, 100%': { boxShadow: '0 0 5px rgba(59, 130, 246, 0.5)' },

326

'50%': { boxShadow: '0 0 20px rgba(59, 130, 246, 0.8)' }

327

});

328

329

const rotate = keyframes({

330

from: { transform: 'rotate(0deg)' },

331

to: { transform: 'rotate(360deg)' }

332

});

333

334

// Combine multiple animations

335

const FloatingGlowBox = styled('div', {

336

width: '100px',

337

height: '100px',

338

backgroundColor: 'blue',

339

borderRadius: '8px',

340

animation: `

341

${float} 3s ease-in-out infinite,

342

${glow} 2s ease-in-out infinite,

343

${rotate} 10s linear infinite

344

`

345

});

346

347

// Sequential animations with delays

348

const SequentialBox = styled('div', {

349

animation: `

350

${fadeIn} 0.5s ease-out,

351

${scaleUp} 0.3s ease-out 0.5s both,

352

${float} 2s ease-in-out 0.8s infinite

353

`

354

});

355

```

356

357

### Performance Optimized Animations

358

359

Create animations optimized for performance using transform and opacity.

360

361

**Usage Examples:**

362

363

```typescript

364

// GPU-accelerated animations

365

const smoothSlide = keyframes({

366

from: {

367

transform: 'translate3d(-100%, 0, 0)',

368

opacity: 0

369

},

370

to: {

371

transform: 'translate3d(0, 0, 0)',

372

opacity: 1

373

}

374

});

375

376

const smoothScale = keyframes({

377

from: {

378

transform: 'scale3d(0.8, 0.8, 1)',

379

opacity: 0

380

},

381

to: {

382

transform: 'scale3d(1, 1, 1)',

383

opacity: 1

384

}

385

});

386

387

const PerformantBox = styled('div', {

388

// Force hardware acceleration

389

willChange: 'transform, opacity',

390

backfaceVisibility: 'hidden',

391

perspective: '1000px',

392

393

variants: {

394

animation: {

395

slide: {

396

animation: `${smoothSlide} 0.3s ease-out`

397

},

398

scale: {

399

animation: `${smoothScale} 0.2s ease-out`

400

}

401

}

402

}

403

});

404

```

405

406

### Animation Utilities

407

408

Helper patterns for common animation scenarios.

409

410

**Usage Examples:**

411

412

```typescript

413

// Staggered animations

414

const staggeredFade = keyframes({

415

from: { opacity: 0, transform: 'translateY(20px)' },

416

to: { opacity: 1, transform: 'translateY(0)' }

417

});

418

419

const StaggeredList = styled('ul', {

420

'& li': {

421

animation: `${staggeredFade} 0.5s ease-out both`,

422

423

'&:nth-child(1)': { animationDelay: '0s' },

424

'&:nth-child(2)': { animationDelay: '0.1s' },

425

'&:nth-child(3)': { animationDelay: '0.2s' },

426

'&:nth-child(4)': { animationDelay: '0.3s' },

427

'&:nth-child(5)': { animationDelay: '0.4s' }

428

}

429

});

430

431

// Infinite loading states

432

const shimmer = keyframes({

433

'0%': { transform: 'translateX(-100%)' },

434

'100%': { transform: 'translateX(100%)' }

435

});

436

437

const LoadingSkeleton = styled('div', {

438

position: 'relative',

439

backgroundColor: '#f0f0f0',

440

overflow: 'hidden',

441

442

'&::after': {

443

content: '""',

444

position: 'absolute',

445

top: 0,

446

right: 0,

447

bottom: 0,

448

left: 0,

449

background: 'linear-gradient(90deg, transparent, rgba(255,255,255,0.8), transparent)',

450

animation: `${shimmer} 1.5s infinite`

451

}

452

});

453

```