LocalMode /ui
Input Controls

Text Processing Panel

A two-column input→output NLP shell — labeled textarea + word count + optional Char Limit Indicator, a result pane with copy, and a run/cancel/clear toolbar.

Text Processing Panel

The Text Processing Panel is a two-column (stacked on mobile) single-input → single-output NLP shell. The left column is a labeled textarea with a live word count and an optional CharLimitIndicator; the right column is a result pane (spinner while processing, pre-wrap text otherwise, or an empty slot) with a copy-with-feedback button. A run / cancel / clear toolbar sits below, and an optional header slot renders above both columns — drop a SegmentedModePicker or LanguagePairSelector there.

It is layout-only. Own the inference in your app by wiring the toolbar to any text-in/text-out hook — useSummarize, useTranslate, useFillMask, useAnswerQuestion, or useGenerateText — and passing result / isProcessing back in.

When to use it: the paste → process → copy layout that recurs across summarization, translation, QA-context, and generation utilities.

Preview

Installation

pnpm dlx shadcn@latest add @localmode/ui/input-controls/text-processing-panel
npx shadcn@latest add @localmode/ui/input-controls/text-processing-panel
yarn dlx shadcn@latest add @localmode/ui/input-controls/text-processing-panel
bunx --bun shadcn@latest add @localmode/ui/input-controls/text-processing-panel

Dependencies

  • Data source: layout-only — renders the result / isProcessing you pass and emits onRun / onCancel / onClear callbacks, so it works with any text-in/text-out backend. Recommended LocalMode producers: useSummarize / useTranslate / useFillMask / useAnswerQuestion / useGenerateText (optional).
  • CharLimitIndicator — composed for the optional limit ring (installed automatically as a registry dependency)
  • lucide-react — icons

Files installed

  • text-processing-panel.tsx — the component
  • char-limit-indicator.tsx — composed for the optional limit ring (registry dependency)
  • lib/utils.ts — the cn() helper (if not already present)

Props

TextProcessingPanel

Prop

Type

Examples

Summarize

import { useState } from 'react';
import { useSummarize } from '@localmode/react';
import { transformers } from '@localmode/transformers';
import { TextProcessingPanel } from '@/components/text-processing-panel';

export function Summarizer() {
  const [text, setText] = useState('');
  const { data, isLoading, execute, cancel, reset } = useSummarize({
    model: transformers.summarizer('Xenova/distilbart-cnn-6-6'),
  });

  return (
    <TextProcessingPanel
      value={text}
      onChange={setText}
      result={data?.summary}
      isProcessing={isLoading}
      onRun={() => execute({ text })}
      onCancel={cancel}
      onClear={reset}
      inputLabel="Article"
      resultLabel="Summary"
      runLabel="Summarize"
    />
  );
}

Translate (header slot)

const { data, isLoading, execute } = useTranslate({ model });
<TextProcessingPanel
  value={text}
  onChange={setText}
  result={data?.translation}
  isProcessing={isLoading}
  onRun={() => execute({ text, sourceLanguage: src, targetLanguage: tgt })}
  header={<LanguagePairSelector {...pairProps} />}
/>

Customization

Pass maxLength to show the CharLimitIndicator under the input. The result pane renders result pre-wrap; for richer output (lists, predictions) drop your own node into emptyState or format result before passing it in. Keep the inference in your app — the panel stays a layout shell with slots. Everything is theme-driven via shadcn/ui CSS variables.

Accessibility

The input textarea has no rendered <label> element, so it takes its accessible name from inputLabel — the same string shown above the column is also wired as the textarea's aria-label. Give each panel a descriptive inputLabel ("Text to summarize", "Source text") and getByLabel(inputLabel) resolves the field uniquely across panels on the same page. The Copy button on the result pane is labelled "Copy result".

On this page