x-container is an accessible, themeable layout container web component for constraining content width, centering page content, and applying consistent responsive spacing.
It is a passive layout primitive:
The component is framework-agnostic and works with plain HTML, React, Reagent, or any framework that supports custom elements.
<x-container>
Provide a low-level layout primitive that can:
| Attribute | Type | Description |
|---|---|---|
as | enum | Semantic root element rendered inside shadow DOM |
size | enum | Max-width preset |
padding | enum | Inline padding preset |
center | boolean-like | Controls horizontal centering |
fluid | boolean | Removes width constraint and stretches full width |
label | string | Accessible label applied to the internal semantic root |
Supported values:
divsectionarticlemainasideheaderfooternavDefault:
div
Invalid values normalize to div.
Supported values:
xssmmdlgxlfullDefault:
lg
Invalid values normalize to lg.
Supported values:
nonesmmdlgDefault:
md
Invalid values normalize to md.
center is a default-true boolean-style option.
Behavior:
center="false" → not centeredThis is exposed as a property for easier programmatic control.
Default:
true
Boolean attribute.
Behavior:
max-width: none; width: 100%Default:
false
Optional string. When provided, it becomes:
aria-label
on the internal semantic root element.
| Property | Type | Description |
|---|---|---|
center | boolean | Reflects layout centering |
fluid | boolean | Reflects full-width fluid mode |
center is implemented as a default-true property:
el.center returns true by defaultel.center = false writes center="false"el.center = true removes the attribute againfluid is a standard reflected boolean property.
x-container emits no custom events.
This is intentional. It is a layout primitive only.
x-container provides a single default slot for arbitrary content.
Example:
<x-container>
<h1>Hello world</h1>
<p>Content goes here.</p>
</x-container>
No named slots are supported.
The host element is always:
<x-container>
But inside shadow DOM, the component renders a semantic root element based on as.
Examples:
<div part="base">
<slot></slot>
</div>
as="section"<section part="base">
<slot></slot>
</section>
as="main"<main part="base" aria-label="Main content">
<slot></slot>
</main>
This allows the component to provide semantic landmarks without changing the host tag.
x-container is intentionally simple.
It guarantees:
asaria-label support via labelExamples:
<x-container as="main" label="Main content"></x-container>
<x-container as="nav" label="Primary navigation"></x-container>
The internal semantic root exposes one stable part:
base
Example:
x-container::part(base) {
background: white;
}
| Variable | Description |
|---|---|
--x-container-max-width-xs | Width for size="xs" |
--x-container-max-width-sm | Width for size="sm" |
--x-container-max-width-md | Width for size="md" |
--x-container-max-width-lg | Width for size="lg" |
--x-container-max-width-xl | Width for size="xl" |
Default values:
xs → 480pxsm → 640pxmd → 768pxlg → 1024pxxl → 1280pxsize="full" removes max-width entirely.
| Variable | Description |
|---|---|
--x-container-padding-sm | Padding for padding="sm" |
--x-container-padding-md | Padding for padding="md" |
--x-container-padding-lg | Padding for padding="lg" |
--x-container-padding-block | Block padding applied to the base element |
Defaults:
sm → 0.5remmd → 1remlg → 1.5rem0| Variable | Description |
|---|---|
--x-container-margin-inline | Margin used for centering |
--x-container-bg | Background |
--x-container-color | Foreground text color |
--x-container-border | Border color |
--x-container-radius | Border radius |
--x-container-shadow | Box shadow |
Defaults:
transparenttransparent0noneSo by default, x-container is layout-first, not card-like.
x-container supports automatic theme adaptation using:
color-scheme: light dark;
@media (prefers-color-scheme: dark) { ... }
Default text tokens:
--x-container-color: #0f172a--x-container-color: #e5e7ebBackground remains transparent by default in both modes.
x-container has no required animated behavior.
It still includes reduced-motion-safe behavior:
@media (prefers-reduced-motion: reduce) {
[part='base'] {
transition: none;
}
}
Since the component does not animate by default, this is mostly defensive.
The component:
data-* attributes on the base partInternal data attributes include:
data-sizedata-paddingdata-centerdata-fluidThis internal projection avoids rewriting host attributes during render.
Default rendered state is effectively:
as = divsize = lgpadding = mdcenter = truefluid = falseSo a plain container:
<x-container></x-container>
renders as a centered large-width container with medium inline padding.
<x-container>
<p>Hello world</p>
</x-container>
<x-container size="sm">
<article>
<h1>Article title</h1>
<p>Readable narrow content width.</p>
</article>
</x-container>
<x-container size="full" padding="lg">
<section>
<h2>Full width layout</h2>
</section>
</x-container>
<x-container as="main" label="Main content">
<h1>Dashboard</h1>
</x-container>
const el = document.querySelector("x-container");
el.center = false;
el.fluid = true;
Example usage with the helper wrapper used in the demo app:
[wc/wc
:x-container
{:size "lg"
:padding "lg"
:center true
:class "page-container"}
[:section.hero-card
[:h1 "Hello world"]
[:p "Content inside a container."]]]
x-container is intentionally minimal.
It owns:
It does not own:
That makes it a strong base primitive for larger layout systems.
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |