Skip to content

Mark

Experimental Alpha

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:

  1. Static Mode: By default, it wraps its content in a <mark> tag, similar to the native HTML element, but styled with AgnosticUI design tokens.
  2. Reactive Mode: When a search prop is provided, the component will dynamically find and highlight substrings within its content that match the search term.

Examples

Vue
Lit
React
Live Preview

Mark Variants

warning
info
success
error
primary
secondary
monochrome

Reactive Highlighting

Case sensitive
Match all

The quick brown fox jumps over the lazy dog. The lazy fox was not the same as the other fox.

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>
    </>
  );
}
Open in StackBlitz

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:

bash
npx ag init --framework FRAMEWORK # react, vue, lit, svelte, etc.
npx ag add Mark

The 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
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
tsx
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)
html
<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
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
tsx
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

PropTypeDefaultDescription
variant'warning' | 'info' | 'success' | 'error' | 'primary' | 'secondary' | 'monochrome''warning'Sets the color variant for the highlight.
searchstringundefinedThe substring to search for and highlight within the component's content. When provided, enables reactive mode.
caseSensitivebooleanfalseIf true, the search will be case-sensitive. Only applies in reactive mode.
matchAllbooleanfalseIf 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.