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:
- no custom events
- no internal interaction model
- no focus management
- no child behavior orchestration
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:
- constrain content width
- center content horizontally
- apply consistent inline padding
- expose a semantic root element
- support light and dark mode theming
- expose surface and spacing tokens for consumers
| 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:
divsectionarticlemainasideheaderfooternav
Default:
div
Invalid values normalize to div.
Supported values:
xssmmdlgxlfull
Default:
lg
Invalid values normalize to lg.
Supported values:
nonesmmdlg
Default:
md
Invalid values normalize to md.
center is a default-true boolean-style option.
Behavior:
- absent attribute → centered
center="false"→ not centered
This is exposed as a property for easier programmatic control.
Default:
true
Boolean attribute.
Behavior:
- absent → normal max-width behavior
- present →
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.centerreturnstrueby default- setting
el.center = falsewritescenter="false" - setting
el.center = trueremoves the attribute again
fluid 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><section part="base">
<slot></slot>
</section><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:
- semantic internal root selected from
as aria-labelsupport vialabel- preservation of slotted child semantics
- no keyboard behavior
- no focus management
- no ARIA role overrides
Examples:
<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→1280px
size="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.5rem- block padding →
0
| 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:
- background →
transparent - border →
transparent - radius →
0 - shadow →
none
So 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: #e5e7eb
Background 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:
- reads host attributes
- normalizes them through the model
- ensures the correct semantic root exists
- writes normalized state to internal
data-*attributes on thebasepart
Internal data attributes include:
data-sizedata-paddingdata-centerdata-fluid
This internal projection avoids rewriting host attributes during render.
Default rendered state is effectively:
as = divsize = lgpadding = mdcenter = truefluid = false
So 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:
- width constraints
- inline spacing
- semantic wrapper selection
- theme-aware layout tokens
It does not own:
- cards
- grids
- sections with internal spacing rules
- interactions
- events
- responsive behavior beyond container width presets
That makes it a strong base primitive for larger layout systems.