Pseudo-selector modifiers enable styling for interactive states and structural positions that can't be applied as inline styles. The framework automatically generates scoped CSS rules for these selectors.
Package: code.yousef.summon.modifier Since: 1.0.0 (enhanced in 0.4.8.4)
Applies styles when the mouse hovers over the element.
Signature:
fun Modifier.hover(hoverModifier: Modifier): Modifier
fun Modifier.hover(styles: Map<String, String>): Modifier
Example:
Box(modifier = Modifier()
.backgroundColor("#007bff")
.hover(Modifier()
.backgroundColor("#0056b3")
.transform("scale(1.05)")
)
)
Generated CSS:
.pseudo-hover-abc123:hover {
background-color: #0056b3;
transform: scale(1.05);
}
Applies styles when the element has keyboard or mouse focus.
Signature:
fun Modifier.focus(focusModifier: Modifier): Modifier
fun Modifier.focus(styles: Map<String, String>): Modifier
Example:
TextField(
modifier = Modifier()
.border("1px solid #ccc")
.focus(Modifier()
.border("2px solid #007bff")
.outline("none")
)
)
Use Cases:
Applies styles when the element is being clicked or pressed.
Signature:
fun Modifier.active(activeModifier: Modifier): Modifier
fun Modifier.active(styles: Map<String, String>): Modifier
Example:
Button(
modifier = Modifier()
.backgroundColor("#007bff")
.active(Modifier()
.backgroundColor("#004085")
.transform("scale(0.98)")
)
)
Use Cases:
Applies styles when the element or any of its descendants have focus.
Signature:
fun Modifier.focusWithin(focusWithinModifier: Modifier): Modifier
fun Modifier.focusWithin(styles: Map<String, String>): Modifier
Example:
Form(modifier = Modifier()
.border("1px solid #ddd")
.focusWithin(Modifier()
.border("2px solid #007bff")
.boxShadow("0 0 0 3px rgba(0,123,255,0.25)")
)
)
Use Cases:
Applies styles to visited links (security restrictions apply).
Signature:
fun Modifier.visited(visitedModifier: Modifier): Modifier
fun Modifier.visited(styles: Map<String, String>): Modifier
Example:
Link(
href = "/page",
modifier = Modifier()
.color("#007bff")
.visited(Modifier()
.color("#6c757d")
)
)
Note: Browsers restrict which styles can be applied for security reasons.
Applies styles to disabled form elements.
Signature:
fun Modifier.disabledStyles(disabledModifier: Modifier): Modifier
fun Modifier.disabledStyles(styles: Map<String, String>): Modifier
Example:
Button(
modifier = Modifier()
.backgroundColor("#007bff")
.disabledStyles(Modifier()
.backgroundColor("#6c757d")
.cursor("not-allowed")
.opacity(0.5)
),
disabled = isDisabled
)
Applies styles to checked checkboxes and radio buttons.
Signature:
fun Modifier.checkedStyles(checkedModifier: Modifier): Modifier
fun Modifier.checkedStyles(styles: Map<String, String>): Modifier
Example:
Checkbox(
modifier = Modifier()
.borderColor("#ccc")
.checkedStyles(Modifier()
.backgroundColor("#007bff")
.borderColor("#007bff")
)
)
Applies styles when the element is the first child of its parent.
Signature:
fun Modifier.firstChild(firstChildModifier: Modifier): Modifier
fun Modifier.firstChild(styles: Map<String, String>): Modifier
Example:
ListItem(modifier = Modifier()
.borderTop("1px solid #ddd")
.firstChild(Modifier()
.borderTop("none")
)
)
Use Cases:
Applies styles when the element is the last child of its parent.
Signature:
fun Modifier.lastChild(lastChildModifier: Modifier): Modifier
fun Modifier.lastChild(styles: Map<String, String>): Modifier
Example:
ListItem(modifier = Modifier()
.borderBottom("1px solid #ddd")
.lastChild(Modifier()
.borderBottom("none")
)
)
Use Cases:
Applies styles based on element position with a pattern.
Signature:
fun Modifier.nthChild(
pattern: String,
nthChildModifier: Modifier
): Modifier
Parameters:
pattern: String - CSS nth-child pattern (e.g., "odd", "even", "2n+1", "3")Example:
// Zebra striping
TableRow(modifier = Modifier()
.backgroundColor("#ffffff")
.nthChild("even", Modifier()
.backgroundColor("#f8f9fa")
)
)
// Every third item
ListItem(modifier = Modifier()
.nthChild("3n", Modifier()
.fontWeight("bold")
)
)
Common Patterns:
"odd" - Odd-numbered children (1, 3, 5, ...)"even" - Even-numbered children (2, 4, 6, ...)"2n+1" - Same as "odd""3n" - Every third child (3, 6, 9, ...)"n+3" - Starting from third child"5" - Only the fifth childApplies styles when the element is the only child of its parent.
Signature:
fun Modifier.onlyChild(onlyChildModifier: Modifier): Modifier
fun Modifier.onlyChild(styles: Map<String, String>): Modifier
Example:
ListItem(modifier = Modifier()
.padding("8px")
.onlyChild(Modifier()
.padding("16px")
.textAlign("center")
)
)
Use Cases:
Button(
onClick = { /* action */ },
label = "Submit",
modifier = Modifier()
.backgroundColor("#007bff")
.color("white")
.padding("10px 20px")
.borderRadius("4px")
.border("none")
.cursor("pointer")
.transition("all", 150)
.hover(Modifier()
.backgroundColor("#0056b3")
.transform("translateY(-2px)")
.boxShadow("0 4px 8px rgba(0,0,0,0.2)")
)
.active(Modifier()
.backgroundColor("#004085")
.transform("translateY(0)")
.boxShadow("0 2px 4px rgba(0,0,0,0.2)")
)
.focus(Modifier()
.outline("none")
.boxShadow("0 0 0 3px rgba(0,123,255,0.5)")
)
)
TextField(
value = value,
onValueChange = { value = it },
modifier = Modifier()
.width("100%")
.padding("8px 12px")
.border("1px solid #ced4da")
.borderRadius("4px")
.transition("border-color", 150)
.focus(Modifier()
.borderColor("#007bff")
.outline("none")
.boxShadow("0 0 0 0.2rem rgba(0,123,255,0.25)")
)
.disabledStyles(Modifier()
.backgroundColor("#e9ecef")
.cursor("not-allowed")
)
)
List(modifier = Modifier()
.listStyle("none")
.padding("0")
) {
items.forEach { item ->
ListItem(modifier = Modifier()
.padding("12px 16px")
.borderBottom("1px solid #dee2e6")
.transition("background-color", 150)
.firstChild(Modifier()
.borderTop("1px solid #dee2e6")
)
.lastChild(Modifier()
.borderBottom("none")
)
.nthChild("odd", Modifier()
.backgroundColor("#f8f9fa")
)
.hover(Modifier()
.backgroundColor("#e9ecef")
.cursor("pointer")
)
) {
Text(item.name)
}
}
}
Card(modifier = Modifier()
.border("1px solid #dee2e6")
.borderRadius("8px")
.padding("20px")
.transition("all", 200)
.hover(Modifier()
.boxShadow("0 4px 12px rgba(0,0,0,0.15)")
.transform("translateY(-4px)")
.borderColor("#007bff")
)
)
<head>// This code:
Box(modifier = Modifier()
.backgroundColor("#007bff")
.hover(Modifier().backgroundColor("#0056b3"))
)
// Generates:
<div class="pseudo-hover-abc123" style="background-color: #007bff;"></div>
<style>
.pseudo-hover-abc123:hover {
background-color: #0056b3;
}
</style>
Modifier()
.transition("all", 200)
.hover(Modifier().backgroundColor("#0056b3"))
Modifier()
.hover(Modifier().backgroundColor("#0056b3"))
.focus(Modifier().borderColor("#007bff"))
.active(Modifier().backgroundColor("#004085"))
// Always include focus styles for keyboard navigation
Button(modifier = Modifier()
.focus(Modifier()
.outline("none")
.boxShadow("0 0 0 3px rgba(0,123,255,0.5)")
)
)
// Good: Use firstChild/lastChild for layout
.firstChild(Modifier().marginTop("0"))
// Avoid: Use nth-child for layout when not necessary
.nthChild("1", Modifier().marginTop("0"))
| Pseudo-Selector | Support | |-----------------|---------------------------------------| | :hover | All browsers | | :focus | All browsers | | :active | All browsers | | :focus-within | Chrome 60+, Safari 10.1+, Firefox 52+ | | :visited | All browsers (limited styles) | | :disabled | All browsers | | :checked | All browsers | | :first-child | All browsers | | :last-child | All browsers | | :nth-child() | All browsers | | :only-child | All browsers |