or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

core-styling.mdcss-utilities.mdindex.mdreact-native.mdserver-side-rendering.mdtest-utilities.mdtheming.mdtypescript-integration.md
tile.json

css-utilities.mddocs/

CSS Utilities

CSS utilities provide helper functions for CSS composition, animations, and global styles. These functions enable advanced styling patterns and reusable style definitions.

css Function

The css helper function creates reusable CSS rule sets that can be shared between styled components or used in template literals.

function css<Props extends object>(
  strings: TemplateStringsArray,
  ...interpolations: Interpolation<Props>[]
): RuleSet<Props>;

function css<Props extends object>(
  styles: StyleFunction<Props> | StyledObject<Props>
): RuleSet<Props>;

type RuleSet<Props> = Interpolation<Props>[];

Usage Examples:

Basic CSS Blocks

import { css } from 'styled-components';

// Reusable style blocks
const centerContent = css`
  display: flex;
  align-items: center;
  justify-content: center;
`;

const buttonBase = css`
  padding: 10px 20px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 16px;
`;

// Use in styled components
const CenteredButton = styled.button`
  ${buttonBase}
  ${centerContent}
  background-color: #007bff;
  color: white;
`;

Dynamic CSS with Props

interface ButtonStyleProps {
  variant?: 'primary' | 'secondary' | 'danger';
  size?: 'small' | 'medium' | 'large';
}

const buttonVariantStyles = css<ButtonStyleProps>`
  background-color: ${props => {
    switch (props.variant) {
      case 'primary': return '#007bff';
      case 'danger': return '#dc3545';
      default: return '#6c757d';
    }
  }};
  
  color: white;
  
  &:hover {
    opacity: 0.8;
  }
`;

const buttonSizeStyles = css<ButtonStyleProps>`
  padding: ${props => {
    switch (props.size) {
      case 'small': return '4px 8px';
      case 'large': return '12px 24px';
      default: return '8px 16px';
    }
  }};
  
  font-size: ${props => {
    switch (props.size) {
      case 'small': return '12px';
      case 'large': return '18px';
      default: return '14px';
    }
  }};
`;

const Button = styled.button<ButtonStyleProps>`
  border: none;
  border-radius: 4px;
  cursor: pointer;
  
  ${buttonVariantStyles}
  ${buttonSizeStyles}
`;

Conditional CSS

interface ConditionalProps {
  isActive?: boolean;
  hasError?: boolean;
  isLoading?: boolean;
}

const conditionalStyles = css<ConditionalProps>`
  ${props => props.isActive && css`
    background-color: #28a745;
    color: white;
  `}
  
  ${props => props.hasError && css`
    border-color: #dc3545;
    background-color: #f8d7da;
  `}
  
  ${props => props.isLoading && css`
    opacity: 0.6;
    cursor: not-allowed;
  `}
`;

const ConditionalComponent = styled.div<ConditionalProps>`
  padding: 10px;
  border: 1px solid #ddd;
  transition: all 0.2s ease;
  
  ${conditionalStyles}
`;

keyframes Function

Creates CSS keyframe animations that can be used in styled components.

function keyframes(
  strings: TemplateStringsArray,
  ...interpolations: Interpolation<any>[]
): Keyframes;

interface Keyframes {
  id: string;
  name: string;
  rules: string;
}

Usage Examples:

Basic Animations

import { keyframes } from 'styled-components';

const fadeIn = keyframes`
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
`;

const slideInLeft = keyframes`
  from {
    transform: translateX(-100%);
  }
  to {
    transform: translateX(0);
  }
`;

const FadeInDiv = styled.div`
  animation: ${fadeIn} 0.3s ease-in;
`;

const SlideInDiv = styled.div`
  animation: ${slideInLeft} 0.5s ease-out;
`;

Complex Animations

const bounce = keyframes`
  0%, 20%, 53%, 80%, to {
    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
    transform: translate3d(0, 0, 0);
  }
  
  40%, 43% {
    animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
    transform: translate3d(0, -30px, 0);
  }
  
  70% {
    animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06);
    transform: translate3d(0, -15px, 0);
  }
  
  90% {
    transform: translate3d(0, -4px, 0);
  }
`;

const pulse = keyframes`
  0% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.05);
  }
  100% {
    transform: scale(1);
  }
`;

const AnimatedButton = styled.button`
  padding: 12px 24px;
  border: none;
  border-radius: 6px;
  background-color: #007bff;
  color: white;
  cursor: pointer;
  
  &:hover {
    animation: ${pulse} 0.6s ease-in-out;
  }
  
  &:active {
    animation: ${bounce} 1s ease-in-out;
  }
`;

Parameterized Animations

const createRotateAnimation = (degrees: number) => keyframes`
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(${degrees}deg);
  }
`;

const rotate360 = createRotateAnimation(360);
const rotate180 = createRotateAnimation(180);

const Spinner = styled.div`
  width: 24px;
  height: 24px;
  border: 2px solid #f3f3f3;
  border-top: 2px solid #007bff;
  border-radius: 50%;
  animation: ${rotate360} 1s linear infinite;
`;

const FlipIcon = styled.div`
  transition: transform 0.3s ease;
  
  &:hover {
    animation: ${rotate180} 0.3s ease-in-out;
  }
`;

createGlobalStyle Function

Creates a component that injects global CSS styles into the document head.

function createGlobalStyle<Props extends object>(
  strings: TemplateStringsArray,
  ...interpolations: Interpolation<Props>[]
): React.ComponentType<ExecutionProps & Props>;

Usage Examples:

Basic Global Styles

import { createGlobalStyle } from 'styled-components';

const GlobalStyle = createGlobalStyle`
  * {
    box-sizing: border-box;
  }
  
  body {
    margin: 0;
    padding: 0;
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
      'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
      sans-serif;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
  }
  
  h1, h2, h3, h4, h5, h6 {
    margin: 0;
    font-weight: 600;
  }
  
  a {
    color: inherit;
    text-decoration: none;
  }
`;

// Usage in React
function App() {
  return (
    <>
      <GlobalStyle />
      <div>Your app content</div>
    </>
  );
}

Theme-based Global Styles

interface GlobalStyleProps {
  theme: {
    colors: {
      background: string;
      text: string;
      primary: string;
    };
    fonts: {
      main: string;
      mono: string;
    };
  };
}

const GlobalStyle = createGlobalStyle<GlobalStyleProps>`
  body {
    background-color: ${props => props.theme.colors.background};
    color: ${props => props.theme.colors.text};
    font-family: ${props => props.theme.fonts.main};
  }
  
  code {
    font-family: ${props => props.theme.fonts.mono};
    background-color: rgba(0, 0, 0, 0.1);
    padding: 2px 4px;
    border-radius: 3px;
  }
  
  ::selection {
    background-color: ${props => props.theme.colors.primary};
    color: white;
  }
`;

// Usage with theme
<ThemeProvider theme={myTheme}>
  <GlobalStyle />
  <App />
</ThemeProvider>

Dynamic Global Styles

interface DynamicGlobalStyleProps {
  isDarkMode?: boolean;
  fontSize?: 'small' | 'medium' | 'large';
}

const DynamicGlobalStyle = createGlobalStyle<DynamicGlobalStyleProps>`
  :root {
    --background-color: ${props => props.isDarkMode ? '#1a1a1a' : '#ffffff'};
    --text-color: ${props => props.isDarkMode ? '#ffffff' : '#333333'};
    --font-size: ${props => {
      switch (props.fontSize) {
        case 'small': return '14px';
        case 'large': return '18px';
        default: return '16px';
      }
    }};
  }
  
  body {
    background-color: var(--background-color);
    color: var(--text-color);
    font-size: var(--font-size);
    transition: background-color 0.3s ease, color 0.3s ease;
  }
  
  ${props => props.isDarkMode && css`
    img {
      filter: brightness(0.8);
    }
  `}
`;

CSS-in-JS Patterns

Media Query Helpers

const sizes = {
  mobile: '768px',
  tablet: '1024px',
  desktop: '1200px'
};

const media = {
  mobile: (content: string) => css`
    @media (max-width: ${sizes.mobile}) {
      ${content}
    }
  `,
  tablet: (content: string) => css`
    @media (max-width: ${sizes.tablet}) {
      ${content}
    }
  `,
  desktop: (content: string) => css`
    @media (min-width: ${sizes.desktop}) {
      ${content}
    }
  `
};

const ResponsiveComponent = styled.div`
  padding: 20px;
  
  ${media.mobile`
    padding: 10px;
    font-size: 14px;
  `}
  
  ${media.tablet`
    padding: 15px;
    font-size: 16px;
  `}
  
  ${media.desktop`
    padding: 30px;
    font-size: 18px;
  `}
`;

Style Mixins

const flexCenter = css`
  display: flex;
  align-items: center;
  justify-content: center;
`;

const absoluteCenter = css`
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
`;

const truncateText = css`
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
`;

const Card = styled.div`
  ${flexCenter}
  padding: 20px;
  border: 1px solid #ddd;
  border-radius: 8px;
`;

const Modal = styled.div`
  ${absoluteCenter}
  background: white;
  border-radius: 8px;
  box-shadow: 0 4px 20px rgba(0,0,0,0.1);
`;

const Title = styled.h2`
  ${truncateText}
  max-width: 300px;
`;

CSS Reset/Normalize

const CSSReset = createGlobalStyle`
  /* Modern CSS Reset */
  *, *::before, *::after {
    box-sizing: border-box;
  }
  
  * {
    margin: 0;
  }
  
  html, body {
    height: 100%;
  }
  
  body {
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
  }
  
  img, picture, video, canvas, svg {
    display: block;
    max-width: 100%;
  }
  
  input, button, textarea, select {
    font: inherit;
  }
  
  p, h1, h2, h3, h4, h5, h6 {
    overflow-wrap: break-word;
  }
  
  #root, #__next {
    isolation: isolate;
  }
`;