- Lab
-
Libraries: If you want this lab, consider one of these libraries.
- Core Tech
Implement Application Styling in Angular
In this Code Lab, learners style an Angular application using component-scoped SCSS and a maintainable styling architecture. They configure component styles and view encapsulation behavior, organize global and component-level styling concerns with Sass, apply predictable low-specificity styling practices, and theme reusable components using host-based selectors and CSS custom properties. The lab focuses on practical implementation of scalable styling patterns in Angular applications.
Lab Info
Table of Contents
-
Challenge
Introduction
Welcome to the Implement Application Styling in Angular lab.
In this hands-on lab, you build out the styling architecture for a multi-component dashboard application by sealing component styles behind view encapsulation, organizing shared Sass into reusable partials, refactoring selectors into a low-specificity BEM structure, and exposing a theme-based surface through
:hostand CSS custom properties.When you complete each task, you run the app and see your work pay off directly in the browser: styles that stay isolated to their own components, a responsive layout driven by a single shared mixin, and a profile form that flips into a dark theme the instant an ancestor class changes.
Concepts involved
View encapsulation is Angular's mechanism for scoping a component's styles to its own template.
Sass partials are
.scssfiles prefixed with an underscore (e.g.,_variables.scss) that exist only to be loaded into other files, never compiled on their own.Sass mixins and functions both let you define reusable logic once and call it from anywhere. A mixin (
@mixin/@include) outputs a block of CSS, whereas a function (@function/@return) computes and returns a single value.BEM (Block, Element, Modifier) is a class-naming convention:
block,block__element,block__element--modifier, keeping every selector a single flat class with equal low specificity.:hostand:host-context()are pseudo-classes available only inside a component's own stylesheet.:hoststyles the component's own root element from the outside-in, whereas:host-context()goes further: it lets a component look outward at its ancestors and change its own styling based on a condition met anywhere above it in the DOM.Prerequisites
Before starting this lab, you should be comfortable with:
- Angular basics: components, templates, and the
@Componentdecorator's metadata - CSS/Sass basics: selectors, specificity, and standard properties
- Basic file-system navigation: creating files and folders inside a given directory structure
The lab environment is ready to use. Your Angular 22 workspace is already scaffolded with four components:
Card,Dashboard,Navbar, andProfileForm, all wired into a workingDashboardview. Each task validates your work by running its corresponding spec file.The scenario
You are a frontend developer building the styling layer for Angular Styling App, a small internal app composed of a navbar, a card grid, and a profile-editing form.
Right now, every component renders correctly but carries no real styling discipline: stylesheets are empty or inconsistent, spacing values are hardcoded in
px, class names do not yet follow a shared convention, and nothing in the app supports more than one visual theme.Your job is to bring this app up to a production-grade styling standard, from sealing each component's styles, through building a shared Sass architecture, to exposing a theme-based dark-mode surface on the profile form.
The application structure
Key files in the lab environment:
src/app/components/card/: a card component rendered three times inside the dashboard gridsrc/app/components/navbar/: the app's top navigation bar, used to demonstrate the difference betweenViewEncapsulation.EmulatedandViewEncapsulation.Nonesrc/app/components/profile-form/: a form component composed inside the dashboardsrc/app/components/dashboard/: the page that composesCardandProfileFormtogethersrc/styles/: the shared Sass directory that you will buildangular.json: the workspace build configuration
Run the application
To visually inspect your changes, start the app by running the following in the terminal:
ng serve --host 0.0.0.0 --port 4200As long as the app is running without errors, your changes update automatically in the browser. You can also open the app in a new browser.
If the app stops running or you need to restart it, press Ctrl+C in the terminal to stop the server, then run the command again.
info> Complete the tasks in order. Each task builds on the previous one.
- Angular basics: components, templates, and the
-
Challenge
View encapsulation
Every component you write in Angular gets its own stylesheet, but by default, those styles do not automatically stay contained. You must understand how Angular seals them off, and what happens when that seal is removed.
In this step, you will connect real Sass styles to the
Cardcomponent for the first time and confirm Angular's defaultViewEncapsulation.Emulatedmode is actually scoping them. Then you will deliberately switch a component toViewEncapsulation.Noneto see what happens when that scoping is turned off, watching one component's styles leak into a completely unrelated part of the app. With your first scoped style in place, you have seen Angular's default sealing behavior (ViewEncapsulation.Emulated) from the inside.Next, you will step outside that seal entirely by switching to
ViewEncapsulation.Noneand watching a style escape its component. You have now seen both sides of view encapsulation: styles that stay locked to their component, and styles that do not.That difference is the foundation everything else in this lab builds on because once you start sharing values like colors and spacing across components in Step 2, you will require that sharing to happen deliberately, through a proper Sass architecture, not by accident through a leaky
ViewEncapsulation.None.warning> Before moving to the next step, remove the
ViewEncapsulation.Noneconfiguration fromnavbar.tsand the.card__titlecolor rule fromcard.scss. -
Challenge
Sass architecture
So far, every style you have written has lived entirely inside one component's own stylesheet, which works fine until two components need to agree on the same color, the same spacing scale, or the same breakpoint. Repeating those values by hand in five different files is how design systems drift apart silently, one small inconsistency at a time.
In this step, you will build the shared foundation that prevents that: a dedicated
styles/directory of Sass partials, wired together through a single forwarding file, and registered with Angular's build so any component can pull from it with one short import. Then you will fill that foundation with shared variables and a responsive mixin. With thestyles/folder created and registered, the plumbing is in place, but every partial inside it is still empty.Next, you will fill
_variables.scssand_mixins.scsswith real values and a real responsive mixin, then apply both directly insideCard. You now have a working Sass architecture: shared variables and a reusable mixin, both accessible from any component via a single import, withCardalready proving the pattern works end-to-end.With that foundation in place, the next problem is selector discipline, making sure the classes you write stay predictable and low-specificity as the app grows.
-
Challenge
Styling practices
With a shared Sass architecture in place, the next thing that can make a stylesheet difficult to maintain isn't missing variables; it's selectors that slowly become harder to override. As nested selectors, long class chains, and inconsistent naming patterns accumulate, specificity keeps increasing. Eventually, even a small style change can turn into a battle that requires
!importantjust to make an override work.In this step, you will use two techniques to keep your styles simple and predictable. First, you will apply BEM's modifier convention to your component class names so variations, such as a "primary" button, can be handled with a single class instead of nested selectors.
Then, you will move away from hardcoded
pxvalues and introduce aremconversion function, allowing spacing and sizing to scale consistently and respect users' accessibility settings.By the end of this step, both your selectors and your measurements will follow the same idea: define a rule once, keep it easy to reuse, and let every component reference it consistently. With a real BEM modifier in place on
Card's button, your class naming follows a consistent, low-specificity pattern.Next, you will apply that same discipline to measurements by replacing hardcoded
pxvalues with a reusablepx-to-remconversion function, so spacing scales consistently everywhere it is used. Your selectors are now flat and predictable, and your spacing scales through a single shared conversion function instead of hardcoded pixels scattered across files. Together, BEM andrem-based tokens mean future style changes like a new button variant or a new spacing scale stay simple with one-place edits.With low-specificity practices in place, the last piece is making components theme-based.
-
Challenge
Theme reusable components
Every style you have written so far has targeted something inside a component's template, but you have never directly styled the component's own root element, the actual tag that Angular renders into the DOM. That gap matters more than it seems: a component dropped into a CSS grid or flex layout behaves unpredictably if its own outer tag has no declared
displaybehavior.In this step, you will first use
:hostto give two components,CardandProfileFormsensible baseline structural styles from the outside-in. Then you will go further, exposing real CSS custom properties onProfileFormso its colors become overridable at runtime; something compiled Sass variables can never do.You will use
:host-context()to letProfileFormdetect a dark-theme class anywhere in its ancestor tree and retheme itself automatically. You will not require any JavaScript toggle or component-level logic. You have now declared baseline layout behavior on bothCardandProfileFormusing:host. Each component takes responsibility for its own root element instead of relying on whatever happens to be styled inside it.Next, you will build on that foundation: exposing real CSS custom properties on
ProfileFormand using:host-context()to let a single ancestor class switch it into a dark theme at runtime.ProfileFormnow exposes its own colors as CSS custom properties and overrides them automatically whenever a.dark-themeclass appears anywhere above it in the DOM.You have just completed a real runtime theme switch which is driven entirely by CSS, with zero JavaScript and no rebuild required to change the active theme.
Conclusion
Across all four steps, you took Angular Styling App from a set of components with empty stylesheets to a properly architected styling system.
- You confirmed Angular's default
ViewEncapsulation.Emulatedkeeps every component's styles sealed off from the rest of the app, and saw firsthand what breaks when that seal is removed underViewEncapsulation.None. - You built a real Sass architecture: partials forwarded through a single entry point, registered with Angular's build so variables, mixins, and functions live in one shared place instead of being repeated across files.
- You adopted BEM's naming convention and a
rem-based conversion function to keep selectors flat and measurements scalable. - And finally, you used
:hostand:host-context()to make components responsible for their own root-element styling and theme-aware without any external logic driving the change.
Putting it all together
These steps are not isolated tricks. They work together. A scoped component that uses shared tokens and low-specificity selectors is easier to maintain. It can safely expose a theme-based API without styles leaking into other parts of the application. It is also less likely to be overridden by unrelated styles.
That is the real goal of a styling architecture. It is not about any single rule. It is about building a set of practices that remain predictable as an application grows far beyond a handful of components.
- You confirmed Angular's default
About the author
Real skill practice before real-world application
Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.
Learn by doing
Engage hands-on with the tools and technologies you’re learning. You pick the skill, we provide the credentials and environment.
Follow your guide
All labs have detailed instructions and objectives, guiding you through the learning process and ensuring you understand every step.
Turn time into mastery
On average, you retain 75% more of your learning if you take time to practice. Hands-on labs set you up for success to make those skills stick.