Mark
This library is a work-in-progress. We are releasing it early to gather feedback, but it is not ready for production.
The Mark component is used to highlight or "mark" a portion of text. It can be used in two modes:
- Static Mode: By default, it wraps its content in a
<mark>tag, similar to the native HTML element, but styled with AgnosticUI design tokens. - Reactive Mode: When a
searchprop is provided, the component will dynamically find and highlight substrings within its content that match the search term.
Examples
Live Preview
Mark Variants
Reactive Highlighting
View Vue Code
<template>
<section class="mbe4">
<h2>Mark Variants</h2>
<div class="flex flex-wrap items-center">
<div class="mis3 mie3">
<VueMark variant="warning">warning</VueMark>
</div>
<div class="mis3 mie3">
<VueMark variant="info">info</VueMark>
</div>
<div class="mis3 mie3">
<VueMark variant="success">success</VueMark>
</div>
<div class="mis3 mie3">
<VueMark variant="error">error</VueMark>
</div>
<div class="mis3 mie3">
<VueMark variant="primary">primary</VueMark>
</div>
<div class="mis3 mie3">
<VueMark variant="secondary">secondary</VueMark>
</div>
<div class="mis3 mie3">
<VueMark variant="monochrome">monochrome</VueMark>
</div>
</div>
</section>
<section class="mbe4">
<h2>Reactive Highlighting</h2>
<div class="flex items-center mbe4">
<VueInput
class="full-width"
v-model:value="searchTerm"
label="Enter text to highlight"
type="text"
/>
</div>
<div class="flex items-center mbe3">
<VueToggle
v-model:checked="caseSensitive"
label="Case sensitive"
/>
<span class="mis2">Case sensitive</span>
</div>
<div class="flex items-center mbe3">
<VueToggle
v-model:checked="matchAll"
label="Match all"
/>
<span class="mis2">Match all</span>
</div>
<div class="mbe4">
<p>
<VueMark
:search="searchTerm"
:caseSensitive="caseSensitive"
:matchAll="matchAll"
variant="warning"
>
The quick brown fox jumps over the lazy dog. The lazy fox was not the same as the other fox.
</VueMark>
</p>
</div>
</section>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import { VueMark } from "agnosticui-core/mark/vue";
import { VueInput } from "agnosticui-core/input/vue";
import { VueToggle } from "agnosticui-core/toggle/vue";
const searchTerm = ref("fox");
const caseSensitive = ref(false);
const matchAll = ref(true);
</script>
Live Preview
View Lit / Web Component Code
import { LitElement, html } from 'lit';
import 'agnosticui-core/mark';
import 'agnosticui-core/input';
import 'agnosticui-core/toggle';
export class MarkLitExamples extends LitElement {
createRenderRoot() {
return this;
}
static get properties() {
return {
searchTerm: { type: String, state: true },
caseSensitive: { type: Boolean, state: true },
matchAll: { type: Boolean, state: true },
};
}
constructor() {
super();
this.searchTerm = 'fox';
this.caseSensitive = false;
this.matchAll = true;
}
handleSearchInput(event) {
this.searchTerm = event.detail.value;
}
handleCaseSensitiveChange(event) {
this.caseSensitive = event.detail.checked;
}
handleMatchAllChange(event) {
this.matchAll = event.detail.checked;
}
render() {
return html`
<section class="mbe4">
<h2>Mark Variants</h2>
<div class="flex flex-wrap items-center">
<div class="mis3 mie3">
<ag-mark variant="warning">warning</ag-mark>
</div>
<div class="mis3 mie3">
<ag-mark variant="info">info</ag-mark>
</div>
<div class="mis3 mie3">
<ag-mark variant="success">success</ag-mark>
</div>
<div class="mis3 mie3">
<ag-mark variant="error">error</ag-mark>
</div>
<div class="mis3 mie3">
<ag-mark variant="primary">primary</ag-mark>
</div>
<div class="mis3 mie3">
<ag-mark variant="secondary">secondary</ag-mark>
</div>
<div class="mis3 mie3">
<ag-mark variant="monochrome">monochrome</ag-mark>
</div>
</div>
</section>
<section class="mbe4">
<h2>Reactive Highlighting</h2>
<div class="flex items-center mbe4">
<ag-input
class="full-width"
.value=${this.searchTerm}
label="Enter text to highlight"
type="text"
@input=${this.handleSearchInput}
></ag-input>
</div>
<div class="flex items-center mbe3">
<ag-toggle
.checked=${this.caseSensitive}
label="Case sensitive"
@change=${this.handleCaseSensitiveChange}
></ag-toggle>
<span class="mis2">Case sensitive</span>
</div>
<div class="flex items-center mbe3">
<ag-toggle
.checked=${this.matchAll}
label="Match all"
@change=${this.handleMatchAllChange}
></ag-toggle>
<span class="mis2">Match all</span>
</div>
<div class="mbe4">
<p>
<ag-mark
search=${this.searchTerm}
?caseSensitive=${this.caseSensitive}
?matchAll=${this.matchAll}
variant="warning"
>
The quick brown fox jumps over the lazy dog. The lazy fox was not the same as the other fox.
</ag-mark>
</p>
</div>
</section>
`;
}
}
// Register the custom element
customElements.define('mark-lit-examples', MarkLitExamples);
Interactive Preview: Click the "Open in StackBlitz" button below to see this example running live in an interactive playground.
View React Code
import { useState } from "react";
import { ReactMark } from "agnosticui-core/mark/react";
import { ReactInput } from "agnosticui-core/input/react";
import { ReactToggle } from "agnosticui-core/toggle/react";
export default function MarkReactExamples() {
const [searchTerm, setSearchTerm] = useState("fox");
const [caseSensitive, setCaseSensitive] = useState(false);
const [matchAll, setMatchAll] = useState(true);
const handleSearchInput = (event) => {
setSearchTerm(event.detail.value);
};
const handleCaseSensitiveChange = (event) => {
setCaseSensitive(event.detail.checked);
};
const handleMatchAllChange = (event) => {
setMatchAll(event.detail.checked);
};
return (
<>
<section className="mbe4">
<h2>Mark Variants</h2>
<div className="flex flex-wrap items-center">
<div className="mis3 mie3">
<ReactMark variant="warning">warning</ReactMark>
</div>
<div className="mis3 mie3">
<ReactMark variant="info">info</ReactMark>
</div>
<div className="mis3 mie3">
<ReactMark variant="success">success</ReactMark>
</div>
<div className="mis3 mie3">
<ReactMark variant="error">error</ReactMark>
</div>
<div className="mis3 mie3">
<ReactMark variant="primary">primary</ReactMark>
</div>
<div className="mis3 mie3">
<ReactMark variant="secondary">secondary</ReactMark>
</div>
<div className="mis3 mie3">
<ReactMark variant="monochrome">monochrome</ReactMark>
</div>
</div>
</section>
<section className="mbe4">
<h2>Reactive Highlighting</h2>
<div className="flex items-center mbe4">
<ReactInput
className="full-width"
value={searchTerm}
label="Enter text to highlight"
type="text"
onInput={handleSearchInput}
/>
</div>
<div className="flex items-center mbe3">
<ReactToggle
checked={caseSensitive}
label="Case sensitive"
onChange={handleCaseSensitiveChange}
/>
<span className="mis2">Case sensitive</span>
</div>
<div className="flex items-center mbe3">
<ReactToggle
checked={matchAll}
label="Match all"
onChange={handleMatchAllChange}
/>
<span className="mis2">Match all</span>
</div>
<div className="mbe4">
<p>
<ReactMark
search={searchTerm}
caseSensitive={caseSensitive}
matchAll={matchAll}
variant="warning"
>
The quick brown fox jumps over the lazy dog. The lazy fox was not the same as the other fox.
</ReactMark>
</p>
</div>
</section>
</>
);
}
Usage
TIP
The framework examples below import AgnosticUI as an npm package. Alternatively, you can use the CLI for complete control, AI/LLM visibility, and full code ownership:
npx ag init --framework FRAMEWORK # react, vue, lit, svelte, etc.
npx ag add MarkThe CLI copies source code directly into your project, giving you full visibility and control. After running npx ag add, you'll receive exact import instructions.
Static Highlighting
To highlight a static piece of text, simply wrap the text with the Mark component.
Vue
<template>
<p>
This is some text with a <VueMark variant="success">highlighted part</VueMark> inside it.
</p>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { VueMark } from 'agnosticui-core/mark/vue';
export default defineComponent({
components: { VueMark }
});
</script>React
import { ReactMark } from 'agnosticui-core/mark/react';
export default function Example() {
return (
<p>
This is some text with a <ReactMark variant="success">highlighted part</ReactMark> inside it.
</p>
);
}Lit (Web Components)
<script type="module">
import 'agnosticui-core/mark';
</script>
<p>
This is some text with a <ag-mark variant="success">highlighted part</ag-mark> inside it.
</p>Reactive Highlighting
To dynamically highlight text, provide the full text as the child of the Mark component and pass a search term as a prop. You can also control the matching behavior with caseSensitive and matchAll.
Vue
<template>
<div class="mbe24">
<vue-input
v-model="searchTerm"
label="Enter text to highlight"
type="text"
/>
</div>
<p>
<VueMark :search="searchTerm" :match-all="true" variant="warning">
The quick brown fox jumps over the lazy dog. The lazy fox was not the same as the other fox.
</VueMark>
</p>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { VueMark } from 'agnosticui-core/mark/vue';
import { VueInput } from 'agnosticui-core/input/vue';
const searchTerm = ref('fox');
</script>React
import { ReactMark } from 'agnosticui-core/mark/react';
import { ReactInput } from 'agnosticui-core/input/react';
import { useState } from 'react';
export default function Example() {
const [searchTerm, setSearchTerm] = useState('fox');
return (
<>
<div style={{ marginBottom: '24px' }}>
<ReactInput
label="Enter text to highlight"
value={searchTerm}
onInput={(e) => setSearchTerm((e.target as HTMLInputElement).value)}
/>
</div>
<p>
<ReactMark search={searchTerm} matchAll={true} variant="warning">
The quick brown fox jumps over the lazy dog. The lazy fox was not the same as the other fox.
</ReactMark>
</p>
</>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
variant | 'warning' | 'info' | 'success' | 'error' | 'primary' | 'secondary' | 'monochrome' | 'warning' | Sets the color variant for the highlight. |
search | string | undefined | The substring to search for and highlight within the component's content. When provided, enables reactive mode. |
caseSensitive | boolean | false | If true, the search will be case-sensitive. Only applies in reactive mode. |
matchAll | boolean | false | If true, all occurrences of the search term will be highlighted. If false, only the first occurrence is highlighted. |
Accessibility
For screen reader users, the component automatically adds visually-hidden text [highlight start] and [highlight end] before and after the highlighted section. This makes the presence of the highlight perceivable to users who may not see the visual styling.