software-mansion / software-mansion/react-native-enriched-html
[Feature request] Attribute-based conditional mention styling (mentionStyleRules)
Nobody has claimed this yet.
- Dominant language
- C
- Stars
- 1.4k
- Forks
- 66
- Avg merge
- 4d 19h
- Merged PRs (30d)
- 11
Description
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) andstyle(MentionStyleProperties) matchis checked against the mention's attributes (the third arg tosetMention, 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
attributesparameter ofsetMentionis already supported but unused for styling. - No codegen changes: Rules are embedded in the existing
mentiondict (which isUnsafeMixed) 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.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Review PR #493 and the proposed JavaScript changes around HtmlStyle and normalizeHtmlStyle, then inspect the iOS InputConfig and MentionStyle.mm implementation described in the issue. Extend the approach for Android and web, preserving indicator-based fallback and first-match rule behavior; done means matching attributes select the configured style across implementations.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- objective-c, react-native, typescript
- Domain
- mobile
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 25/100