css.marker / css.extended
API reference for css.marker and css.extended - Context-aware styling without DOM structure dependency
export type marker = (id: string, pseudo: string) => Marker;
export const marker: marker;
export type extended = <I extends string, P extends string>(id: I, pseudo: P) => Extended<I, P>;
export const extended: extended;The marker and extended APIs enable context-aware styling without relying on rigid DOM hierarchies (such as strict parent-child nesting) or combinator syntax. These paired APIs maintain atomicity while allowing child elements to respond to parent states.
Production Ready - These APIs compile to CSS Container Style Queries (@container style()). Since Firefox 151, style queries are fully supported across all major modern browsers (Chrome/Edge, Safari, and Firefox), making marker and extended completely stable for production use.
marker(id, pseudo)- Sets a CSS variable marker on a parent elementextended(id, pseudo)- Applies styles to children when the marker is active
Parameters
The parameters must be linked (match) in both cases.
id- A unique identifier linking the marker and extended stylespseudo- The pseudo-class state (e.g.,':hover',':focus',':active')
Example
import * as css from '@plumeria/core';
const animation = css.keyframes({
'0%': {
scale: 1.2,
},
'50%': {
scale: 1.3,
},
'100%': {
scale: 1.2,
},
});
const styles = css.create({
grand: {
display: 'flex',
flexDirection: 'column',
gap: 15,
alignItems: 'center',
justifyContent: 'center',
width: '100%',
minHeight: 250,
padding: 20,
border: '2px dashed #c4c4c466',
borderRadius: 12,
transition: 'all 0.3s',
...css.marker('grand', ':hover'),
},
parent: {
display: 'flex',
flexDirection: 'column',
gap: 10,
alignItems: 'center',
justifyContent: 'center',
width: '80%',
minHeight: 120,
padding: 10,
backgroundColor: '#f5f5f7',
border: '2px solid #c4c4c444',
borderRadius: 8,
transition: 'all 0.3s',
...css.marker('parent', ':hover'),
},
child: {
padding: '8px 16px',
fontWeight: 'bold',
color: '#86868b',
background: '#e8e8ed',
borderRadius: 6,
transition: 'all 0.3s',
[css.extended('grand', ':hover')]: {
color: '#0066cc',
background: '#e1f0ff',
},
[css.extended('parent', ':hover')]: {
color: '#ffffff',
background: '#ff9500',
scale: 1.2,
':hover': {
background: 'skyblue',
animationName: animation,
animationDuration: '1.2s',
animationTimingFunction: 'ease-in-out',
animationIterationCount: 'infinite',
},
},
},
discription: {
fontSize: '14px',
color: '#86868b',
},
});
const MarkerExtended = () => {
return (
<div styleName={styles.grand}>
<span styleName={styles.discription}>Grand Container (Hover me)</span>
<div styleName={styles.parent}>
<span styleName={styles.discription}>Parent Container (Hover me too)</span>
<div styleName={styles.child}>Child Element</div>
</div>
</div>
);
};.xtkxh191:hover {
--grand-hover: 1;
}
.xhcsnlrf:hover {
--parent-hover: 1;
}
@container style(--grand-hover: 1) {
.x84muc4x:not(#\#) {
color: #06c;
}
.x2x6k4j2:not(#\#):not(#\#) {
background-color: #e1f0ff;
}
}
@container style(--parent-hover: 1) {
.xr8ck8y9:not(#\#) {
color: #fff;
}
.xb1yp2w2:not(#\#):not(#\#) {
background-color: #ff9500;
}
.xewf73ay:not(#\#) {
scale: 1.3;
}
.x8odz1r5:not(#\#):not(#\#) {
animation-name: kf-xmortmuw;
}
.x0guwijo:not(#\#):not(#\#) {
animation-duration: 1.2s;
}
.xek6euru:not(#\#):not(#\#) {
animation-timing-function: ease-in-out;
}
.xwdc6dqv:not(#\#):not(#\#) {
animation-iteration-count: infinite;
}
.xd9yj17o:not(#\#):hover {
color: #0ff;
}
}How it works
Internal
marker() generates a CSS variable when the pseudo-class is active:
.parent:hover {
--ul-hover: 1;
}extended() wraps child styles in a container query:
@container style(--ul-hover: 1) {
.child { /* styles */ }
}The CSS variable acts as a signal that propagates to descendants without DOM structure dependency.
ESLint Rule
The no-combinator rule enforces this pattern by disallowing combinator syntax.