Skip to content

feat: Attribute-based conditional mention styling (mentionStyleRules) #494

@ramcav

Description

@ramcav

Problem

Currently, mention styling is determined entirely by the indicator character — all mentions with the same indicator share one style. There's no way to style individual mentions differently based on their state or metadata.

Use case: In our app, we use mentions for template variables (%custom_var% and {{mapping_var}}). Some variables are "pending" (not yet configured by the user) and need to be visually distinct — e.g., orange instead of blue — so users can see at a glance which variables need attention. Since both valid and pending variables share the same indicator, we can't differentiate them with the current API.

Proposed API

A new mentionStyleRules property on htmlStyle that allows declarative, attribute-based style overrides:

<EnrichedTextInput
  htmlStyle={{
    mention: {
      "@": { color: "blue", backgroundColor: "lightblue", textDecorationLine: "none" },
    },
    mentionStyleRules: [
      {
        match: { pending: "true" },
        style: { color: "orange", backgroundColor: "lightyellow", textDecorationLine: "none" },
      },
      {
        match: { type: "urgent", priority: "high" },
        style: { color: "red", backgroundColor: "pink", textDecorationLine: "underline" },
      },
    ],
  }}
  mentionIndicators={["@"]}
/>

When committing a mention with matching attributes:

ref.current?.setMention("@", "John", { pending: "true" });
// → renders with orange style instead of the default blue

How it works

  • Each rule has match (key-value pairs) and style (MentionStyleProperties)
  • match is checked against the mention's attributes (the third arg to setMention, which are already stored on both iOS and Android)
  • First matching rule wins; unmatched mentions fall back to indicator-based style
  • Fully declarative — no lambdas, serializable over the bridge

Why this design

  • No indicator hacking: We tried using separate indicator characters for different states, but indicators are tightly coupled to detection triggers and the native editor displays them as visible prefixes.
  • Composable: Multiple rules for different conditions, each with independent match criteria.
  • Backwards compatible: No rules = existing behavior. The attributes parameter of setMention is already supported but unused for styling.
  • No codegen changes: Rules are embedded in the existing mention dict (which is UnsafeMixed) and extracted on the native side.

Implementation

I have a working iOS implementation in PR #493. Happy to adjust the approach based on feedback. The Android and web implementations would follow the same pattern.

Summary of changes

JS: mentionStyleRules on HtmlStyle, processed in normalizeHtmlStyle (color conversion), embedded as __rules__ in the mention dict for native transport.

iOS native: InputConfig stores rules and exposes mentionStylePropsForIndicator:attributes: which deserializes the mention's JSON attributes and matches against rules. MentionStyle.mm uses the attribute-aware lookup.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions