LogoLogo
HomeDiscourseBlogDiscord
  • Introduction
  • Introduction
    • Quick start
    • Aurelia for new developers
    • Hello world
      • Creating your first app
      • Your first component - part 1: the view model
      • Your first component - part 2: the view
      • Running our app
      • Next steps
  • Templates
    • Template Syntax
      • Attribute binding
      • Event binding
      • Text interpolation
      • Template promises
      • Template references
      • Template variables
      • Globals
    • Custom attributes
    • Value converters (pipes)
    • Binding behaviors
    • Form Inputs
    • CSS classes and styling
    • Conditional Rendering
    • List Rendering
    • Lambda Expressions
    • Local templates (inline templates)
    • SVG
  • Components
    • Component basics
    • Component lifecycles
    • Bindable properties
    • Styling components
    • Slotted content
    • Scope and context
    • CustomElement API
    • Template compilation
      • processContent
      • Extending templating syntax
      • Modifying template parsing with AttributePattern
      • Extending binding language
      • Using the template compiler
      • Attribute mapping
  • Getting to know Aurelia
    • Routing
      • @aurelia/router
        • Getting Started
        • Creating Routes
        • Routing Lifecycle
        • Viewports
        • Navigating
        • Route hooks
        • Router animation
        • Route Events
        • Router Tutorial
        • Router Recipes
      • @aurelia/router-lite
        • Getting started
        • Router configuration
        • Configuring routes
        • Viewports
        • Navigating
        • Lifecycle hooks
        • Router hooks
        • Router events
        • Navigation model
        • Transition plan
    • App configuration and startup
    • Enhance
    • Template controllers
    • Understanding synchronous binding
    • Dynamic composition
    • Portalling elements
    • Observation
      • Observing property changes with @observable
      • Effect observation
      • HTML observation
      • Using observerLocator
    • Watching data
    • Dependency injection (DI)
    • App Tasks
    • Task Queue
    • Event Aggregator
  • Developer Guides
    • Animation
    • Testing
      • Overview
      • Testing attributes
      • Testing components
      • Testing value converters
      • Working with the fluent API
      • Stubs, mocks & spies
    • Logging
    • Building plugins
    • Web Components
    • UI virtualization
    • Errors
      • 0001 to 0023
      • 0088 to 0723
      • 0901 to 0908
    • Bundlers
    • Recipes
      • Apollo GraphQL integration
      • Auth0 integration
      • Containerizing Aurelia apps with Docker
      • Cordova/Phonegap integration
      • CSS-in-JS with Emotion
      • DOM style injection
      • Firebase integration
      • Markdown integration
      • Multi root
      • Progress Web Apps (PWA's)
      • Securing an app
      • SignalR integration
      • Strongly-typed templates
      • TailwindCSS integration
      • WebSockets Integration
      • Web Workers Integration
    • Playground
      • Binding & Templating
      • Custom Attributes
        • Binding to Element Size
      • Integration
        • Microsoft FAST
        • Ionic
    • Migrating to Aurelia 2
      • For plugin authors
      • Side-by-side comparison
    • Cheat Sheet
  • Aurelia Packages
    • Validation
      • Validation Tutorial
      • Plugin Configuration
      • Defining & Customizing Rules
      • Architecture
      • Tagging Rules
      • Model Based Validation
      • Validation Controller
      • Validate Binding Behavior
      • Displaying Errors
      • I18n Internationalization
      • Migration Guide & Breaking Changes
    • i18n Internationalization
    • Fetch Client
      • Overview
      • Setup and Configuration
      • Response types
      • Working with forms
      • Intercepting responses & requests
      • Advanced
    • Event Aggregator
    • State
    • Store
      • Configuration and Setup
      • Middleware
    • Dialog
  • Tutorials
    • Building a ChatGPT inspired app
    • Building a realtime cryptocurrency price tracker
    • Building a todo application
    • Building a weather application
    • Building a widget-based dashboard
    • React inside Aurelia
    • Svelte inside Aurelia
    • Synthetic view
    • Vue inside Aurelia
  • Community Contribution
    • Joining the community
    • Code of conduct
    • Contributor guide
    • Building and testing aurelia
    • Writing documentation
    • Translating documentation
Powered by GitBook
On this page
  • What is CSS-in-JS?
  • Why Emotion?
  • Integrating Emotion with Aurelia 2
  • 1. Install Emotion
  • 2. Create a Custom Attribute
  • Explanation of Key Concepts
  • 3. Register the Custom Attribute
  • 4. Apply Styles in Components
  • Considerations

Was this helpful?

Export as PDF
  1. Developer Guides
  2. Recipes

CSS-in-JS with Emotion

What is CSS-in-JS?

CSS-in-JS is a technique where JavaScript is used to style components. This approach encapsulates styles within components, making the code more declarative and maintainable.

Why Emotion?

Emotion is a highly performant and flexible CSS-in-JS library that is framework-agnostic, making it ideal for use with Aurelia 2. It provides:

  • String and object-based styling.

  • Predictable composition to avoid specificity issues.

  • A great developer experience with source maps and labels.

  • Heavy caching for optimized performance.

Integrating Emotion with Aurelia 2

To integrate Emotion with Aurelia 2, follow these steps.

1. Install Emotion

Install the framework-agnostic version of Emotion:

npm install @emotion/css

2. Create a Custom Attribute

Define a custom attribute to apply Emotion styles, ensuring it works for both Shadow DOM and non-Shadow DOM scenarios.

// src/resources/attributes/emotion.ts
import { resolve } from 'aurelia';
import { css, cache } from '@emotion/css';

export class EmotionCustomAttribute {
  private element: Element = resolve(Element);

  attached() {
    if (this.isInShadow(this.element)) {
      cache.sheet.container = (this.element.getRootNode() as ShadowRoot).querySelector('style') || this.element.getRootNode();
    } else {
      cache.sheet.container = document.head;
    }

    this.element.classList.add(css(this.value));
  }

  private isInShadow(element: Element): boolean {
    return element.getRootNode() instanceof ShadowRoot;
  }
}

Explanation of Key Concepts

  • Shadow DOM Handling: If the element is inside a Shadow DOM, Emotion will inject styles into the shadow root rather than the document head. This ensures styles are properly scoped.

  • cache.sheet.container: Emotion uses this setting to define where styles are injected.

    • For Shadow DOM, styles are injected into the shadow root.

    • For regular DOM, styles are injected into <head>.

  • Why attached()? The attached() lifecycle hook ensures that the element is in the DOM before determining its shadow state.

3. Register the Custom Attribute

Register the custom attribute in your Aurelia application:

// src/main.ts
import Aurelia from 'aurelia';
import { EmotionCustomAttribute } from './resources/attributes/emotion';
import { MyApp } from './my-app';

Aurelia
  .register(EmotionCustomAttribute)
  .app(MyApp)
  .start();

4. Apply Styles in Components

Use the emotion custom attribute in your components:

// src/my-app.ts
export class MyApp {
  public message = 'Hello World!';
  public cssObject = {
    backgroundColor: 'hotpink',
    '&:hover': {
      color: 'white'
    }
  };
}
<!-- src/my-app.html -->
<template>
  <div emotion.bind="cssObject">${message}</div>
</template>

Considerations

  • Shadow DOM Support: If you're using Shadow DOM in Aurelia, Emotion will automatically inject styles into the correct shadow root.

  • Performance Implications: CSS-in-JS solutions like Emotion introduce runtime overhead. If performance is a concern, consider Emotion’s static extraction capabilities.

By following this guide, you ensure that Emotion integrates seamlessly with Aurelia 2 while supporting both Shadow DOM and standard DOM rendering.

PreviousCordova/Phonegap integrationNextDOM style injection

Last updated 2 months ago

Was this helpful?