Sass meta.content-exists() Function

Beginner
⏱️ 10 min read
📚 Updated: Jul 2026
🎯 5 Examples
sass:meta · mixin only

What You’ll Learn

meta.content-exists() belongs to the built-in sass:meta module. It tells you whether the current mixin was given a @content block. This page covers safe defaults, vs meta.accepts-content, the “inside a mixin only” rule, and five compiled examples.

01

Concept

Was @content passed?

02

Module

@use "sass:meta"

03

Returns

true / false

04

Scope

Inside mixins only

05

vs accepts

Passed vs can accept

06

Practice

5 examples

What Is meta.content-exists()?

Mixins can optionally receive a block of styles with @content:

styles.scss
@include card;                 // no content block
@include card { color: navy; } // content block passed

Official docs: meta.content-exists() returns whether the current mixin was passed a @content block. Use that boolean in @if to change padding, wrappers, or fallback styles when callers omit the block.

💡
Beginner tip

Think of a gift bag: content-exists asks “did someone put something in the bag on this call?” It does not ask “can this bag hold gifts?”—that is meta.accepts-content.

📝 Syntax

styles.scss
@use "sass:meta";

// Recommended — no parameters
meta.content-exists()

// Legacy global name
content-exists()

Parameters

None. The function inspects the mixin that is currently running.

Return value

TypeResult
Booleantrue if a @content block was passed; otherwise false

Errors

Official docs: throws an error if called outside of a mixin. Keep it inside @mixin … { … }.

📦 Loading sass:meta

styles.scss
// Recommended — namespaced
@use "sass:meta";

@mixin demo {
  @if meta.content-exists() {
    @content;
  }
}

// Optional — bring members into scope
@use "sass:meta" as *;

@mixin demo {
  @if content-exists() {
    @content;
  }
}

// Legacy global
@mixin demo {
  @if content-exists() {
    @content;
  }
}

🔗 How @content Fits In

  1. Define a mixin that may include @content.
  2. Callers either @include it bare, or with a { … } block.
  3. Inside the mixin, meta.content-exists() reports which form was used.
  4. Emit @content when you want the caller’s styles inserted.
styles.scss
@use "sass:meta";

@mixin panel {
  border: 1px solid #ddd;
  @if meta.content-exists() {
    padding: 1rem;
    @content;
  }
}

📋 content-exists vs accepts-content

meta.content-existsmeta.accepts-content
QuestionWas @content passed this include?Can this mixin value take @content?
ArgumentsNoneA mixin value (meta.get-mixin)
WhereInside the mixin bodyAnywhere you hold a mixin value
Dart SassLong-standing helper1.69+

🛠 Compatibility

This is about Sass compilers, not browsers. The check runs at compile time.

Implementationcontent-exists
Dart SassYes — prefer meta.content-exists with sass:meta
LibSassYes (legacy global / pipelines)
Ruby SassYes (legacy global / pipelines)

Prefer current Dart Sass and the namespaced meta. form.

⚡ Quick Reference

GoalCode
Import meta@use "sass:meta";
Check for contentmeta.content-exists()
Branch on it@if meta.content-exists() { … }
Insert caller styles@content;
Ask “can accept?”meta.accepts-content($mixin)
AvoidCalling outside a mixin

Examples Gallery

Each example calls meta.content-exists() inside a mixin. Open View Compiled CSS for verified Dart Sass output.

📚 Getting Started

Bare include vs content block, and optional padding.

Example 1 — Basic True / False Branch

Emit different CSS depending on whether a content block was passed.

styles.scss
@use "sass:meta";

@mixin status {
  @if meta.content-exists() {
    --has-content: true;
    @content;
  } @else {
    --has-content: false;
  }
}

.bare {
  @include status;
}

.filled {
  @include status {
    color: teal;
  }
}

How It Works

.bare includes the mixin without braces—false. .filled passes a block—true, then @content inserts color: teal.

Example 2 — Fallback Styles When No Content

Provide a default message style when callers skip the content block.

styles.scss
@use "sass:meta";

@mixin alert {
  border-left: 4px solid #f59e0b;
  padding: 0.75rem 1rem;
  @if meta.content-exists() {
    @content;
  } @else {
    color: #92400e;
    font-weight: 600;
  }
}

.custom {
  @include alert {
    color: #1e3a8a;
  }
}

.fallback {
  @include alert;
}

How It Works

Shared chrome (border + padding) always emits. Content controls the text color path; no content uses the amber fallback.

📈 Practical Patterns

Wrappers, markers, and empty content blocks.

Example 3 — Optional Inner Wrapper

Only wrap children when the caller actually provides styles.

styles.scss
@use "sass:meta";

@mixin card {
  background: #fff;
  border-radius: 8px;
  @if meta.content-exists() {
    .card__body {
      padding: 1.25rem;
      @content;
    }
  }
}

.shell {
  @include card;
}

.body {
  @include card {
    font-size: 1rem;
  }
}

How It Works

Without content, only the shell styles compile. With content, Sass nests .card__body and inserts the caller’s rules.

Example 4 — Marker That Reflects Content

Change a custom property based on whether content was supplied.

styles.scss
@use "sass:meta";

@mixin section {
  display: block;
  --mode: #{if(meta.content-exists(), "rich", "plain")};
  @content;
}

.plain {
  @include section;
}

.rich {
  @include section {
    margin-block: 2rem;
  }
}

How It Works

if(meta.content-exists(), …) is a compact expression form of the same check. @content still runs when present (and is a no-op when absent).

Example 5 — Empty Content Block Still Counts

Braces with no declarations still pass a content block.

styles.scss
@use "sass:meta";

@mixin flag {
  --passed: #{meta.content-exists()};
  @content;
}

.none {
  @include flag;
}

.empty {
  @include flag {
  }
}

How It Works

content-exists answers “was a block passed?”, not “does the block contain CSS?” Empty braces still yield true.

🚀 Real-World Use Cases

  • Optional layout chrome — padding, wrappers, or gaps only when content exists.
  • Fallback copy styles — default color/weight when callers skip the block.
  • Debug / theme flags — set custom properties like --has-content for tooling.
  • Component APIs — one mixin that works as a shell or as a filled component.
  • Safer @content — branch before nesting content into deep selectors.

🧠 How Compilation Works

1

Include the mixin

Caller uses bare @include or passes a { … } block.

Source
2

Ask content-exists

Inside the mixin, Sass answers true or false for this include.

Compile
3

Branch and @content

@if picks styles; @content inserts the caller block when present.

Expand
4

CSS ships

Browsers never see meta.content-exists—only finished rules.

⚠️ Common Pitfalls

  • Calling outside a mixin — official docs: this throws an error.
  • Confusing with accepts-content — that checks capability on a mixin value, not this include.
  • Empty braces surprise@include m { } still counts as content passed.
  • Forgetting @content — detecting content is useless if you never insert it.
  • Expecting runtime checks — everything resolves when Sass compiles.

💡 Best Practices

✅ Do

  • Use @use "sass:meta" and meta.content-exists()
  • Call it only inside @mixin
  • Pair with @if for optional chrome / fallbacks
  • Document whether your mixin expects content
  • Prefer Dart Sass for modern modules

❌ Don’t

  • Call it at the root of a stylesheet
  • Assume empty { } means false
  • Mix it up with meta.accepts-content
  • Expect the browser to evaluate it
  • Skip @content when you intend to forward styles

Key Takeaways

Knowledge Unlocked

Five things to remember about meta.content-exists()

Detect whether this mixin include received a @content block.

5
Core concepts
📦 02

Module

sass:meta

@use
03

Returns

boolean

Result
🔒 04

Scope

mixin only

Safe
05

vs accepts

passed vs can

Compare

❓ Frequently Asked Questions

meta.content-exists() returns true or false for whether the current mixin was passed a @content block when it was included.
Only inside a mixin. Official docs: calling it outside a mixin throws an error.
content-exists answers “did this include pass @content?” for the mixin running now. accepts-content answers “can this mixin value take @content?” before you apply it.
Yes. If the caller writes @include my-mixin { }, a content block was still passed, so content-exists() is typically true even when the block is empty.
Yes. content-exists() is the legacy global name. Prefer meta.content-exists after @use "sass:meta".
No. It runs at compile time. Browsers only see the CSS your mixin emits after the @if branches resolve.
Did you know?

Official Sass docs demonstrate meta.content-exists() with @debug inside a mixin: bare @include prints false, and an include with a content block prints true—the same boolean your @if branches use.

Conclusion

meta.content-exists() returns whether the mixin you are inside received a @content block. Use it for optional wrappers and fallbacks, call it only inside mixins, and reach for meta.accepts-content when you need to inspect a mixin value ahead of time.

Continue with meta.feature-exists() or the Sass introduction.

Next: deprecated feature flags

Learn why meta.feature-exists() is deprecated and how to remove it.

meta.feature-exists() →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

5 people found this page helpful