The acts and fields counsel touches: buttons in five weights, text, search, choices, the combobox, attaching files, correcting a fact in place, and the Paper · Lamp switch.
One field, one binding act, two destinations. Everything on this plate is a package control; nothing is restyled.
Paper
Lamp
01
Button
One clear next act. The binding fill is kept for the act the page exists for; the letter act (Send, Open a matter) is set in ink; everything else is ruled or quiet.
Anatomy
.preceda-button
Primary (the 0.1 default): binding fill, action ink, Inter 14, 40px tall.
--secondary
Rule-strong border, ink text, transparent; paper-hover under the hand.
--quiet
Binding-ink text only; binding tint on hover. The least weight an act can have.
--ink
The letter act: ink fill, paper text, set in the serif. Lamp inverts it by itself.
--destructive
Binding rule and binding-ink verb; fills with binding only on hover. The word says what is lost.
--icon
Square, icon only; an aria-label is required (IconButton enforces it).
--sm
32px drawn, 40px hit area (44px on touch) via an invisible extension.
__working
The working point: a small square in the text colour, pulsing unless motion is reduced.
.preceda-button-group
Related acts on one line (role="group"). --attached shares rules; --end aligns right.
Variants
Primary
One per view.
Paper
Lamp
Secondary
Paper
Lamp
Quiet
Paper
Lamp
Ink
The composer’s Send and the register’s Open a matter. Interactive: press Send.
Paper
Lamp
Destructive
Name the loss. Confirmation belongs to ConfirmDialog (T4).
Paper
Lamp
Icon only
Paper
Lamp
Sizes
md (40px) is the default; sm for dense rows.
Paper
Lamp
Loading
Present-tense label and the working point. Focus stays on the button.
Paper
Lamp
Group
Paper
Lamp
State matrix
StatePaperLamp
default
hover
focus-visible
active
disabled
loading
At 390 px
On a coarse pointer every button grows to 44px. In a sheet or on the register, the one act runs full width at the foot; a second act sits above it as secondary.
390 px
Accessibility
Native <button type="button"> by default; asChild renders a router link with the same face when the act navigates.
Loading sets aria-busy and aria-disabled (not disabled), so focus and the accessible name stay while the label reads “Sending…”.
IconButton requires label; the glyph is aria-hidden. Never rely on title= for a name.
Disabled is flat paper-sunken with tertiary ink and no hover; explain why nearby, or prefer an error on submit.
Targets: 40px (32px drawn + extension for sm); 44px under pointer: coarse.
Do
Write the act as a verb and its object: “Approve for filing”, “Delete this draft”.
Use ink for the letter act — the one that sends words to the associate or opens a new matter.
Keep one primary per view; pair it with a secondary when there is a way back.
Don’t
Put two binding fills side by side, or use destructive for anything reversible.
Use an icon-only button where a word fits; “More” is the exception.
Animate the label or swap it for a spinner; the working point is the only motion.
import { Button, ButtonGroup, IconButton } from '@luvkapur/preceda-design-system/react';
<Button variant="ink" loading={sending} loadingLabel="Sending…" data-matter-send onClick={send}>Send</Button>
<IconButton icon="more" label="More actions on this matter" />
<Button asChild variant="secondary"><RouterLink to="/matters">Back to matters</RouterLink></Button>
<ButtonGroup aria-label="Filing">
<Button variant="secondary">Return to associate</Button>
<Button>Approve for filing</Button>
</ButtonGroup>
02
Text field
A labelled line for short data: an address, a code, a case number. The label sits above in small caps, the hint and the error below, and the error is announced with the field.
Anatomy
.preceda-field-group
The stack: label, control, then the foot (error before hint).
.preceda-field-label
Small-caps label role in secondary ink; __optional adds “· optional” in tertiary.
.preceda-field
The 0.1 control: rule-strong border on paper-raised, Inter 14, 40px. Hover darkens the rule; focus draws the opaque ring.
--code
One-time codes and identifiers: mono, tabular, tracked, centred.
--ruled
Only a bottom rule, in the serif: an answer written inside a letter or fact request.
.preceda-field-hint / .preceda-field-error
Small role; the error is binding ink with a leading dash and is referenced by aria-describedby.
Variants
Default
Paper
We send a six-digit code; there is no password.
Lamp
We send a six-digit code; there is no password.
Code
The sign-in code: numeric keypad, one-time-code autocomplete.
Paper
Lamp
Ruled
An answer set within correspondence (the associate’s numbered questions).
Paper
Lamp
Optional
Paper
Lamp
State matrix
StatePaperLamp
empty
filled
hover
focus-visible
error
Enter the whole address, e.g. rhea@mehrachambers.in.
Enter the whole address, e.g. rhea@mehrachambers.in.
disabled
Sending the code…
Sending the code…
read-only
At 390 px
Full width, 44px tall on touch, and set at 17px under a coarse pointer so iOS does not zoom into the field. Use the right type, inputMode and autoComplete so the phone offers the right keyboard and the code from Messages.
390 px
Accessibility
A visible <label for> is always present; placeholder text is an example, never the label.
The error sets aria-invalid and is listed first in aria-describedby, then the hint.
Placeholder ink is tertiary (passes 4.5:1); disabled values stay in tertiary ink, legible but inert.
Focus ring is the shared opaque binding outline, offset 2px.
Do
Say what the field wants in the label and give an example in the placeholder.
Write errors as the fix: “Enter the whole address…”.
Don’t
Use placeholder text as the only label.
Validate on every keystroke; validate on blur or submit.
Counsel’s own writing, set in the reading serif. It grows with what is written up to a cap, then scrolls; it never shows a resize grip in the composer.
Anatomy
.preceda-field--textarea
Serif body (15/1.55); rows sets the resting height, no resize grip.
TextArea autoGrow
React fallback: measures scrollHeight on every change, capped at maxRows lines, then overflow scrolls.
onSubmitShortcut
The composer pattern: Enter submits a non-blank value, Shift+Enter inserts a newline, IME composition is respected.
.preceda-field-counter
Optional “n / max” under the field when showCount and maxLength are set.
--resizable
autoGrow={false}: fixed height with a vertical grip, for long notes outside the composer.
Variants
Instruction (interactive)
Type, press Enter to send, Shift+Enter for a new line.
Paper
Enter sends · Shift+Enter starts a new line
Lamp
Enter sends · Shift+Enter starts a new line
With count
Paper
85 / 500
Lamp
85 / 500
Grown to its cap
Paper
Lamp
State matrix
StatePaperLamp
empty
hover
focus-visible
error
State at least one ground before the associate drafts.
State at least one ground before the associate drafts.
disabled
The associate is working; you can write again when it replies.
The associate is working; you can write again when it replies.
At 390 px
In the dock the composer is one line that grows to four before it scrolls, so the desk stays in view. Under a coarse pointer the serif rises to the 17px reading size so iOS does not zoom into the field.
390 px
Accessibility
Label it: a visible label, or aria-label (“Instruct the associate”) where the placeholder carries the prompt.
Explain the Enter/Shift+Enter shortcut in the hint; it is announced with the field.
The counter is referenced by aria-describedby but not live, so it is not read on every keystroke.
Do
Keep the composer placeholder an invitation to ask or instruct: “Ask a question or instruct the associate…”.
Cap growth so the send act never leaves the viewport.
Don’t
Show a resize grip in the composer.
Clear what counsel wrote when a send fails.
Usage
HTML
<textarea class="preceda-field preceda-field--textarea" rows="2"
aria-label="Instruct the associate" placeholder="Ask a question or instruct the associate…"></textarea>
React
import { TextArea } from '@luvkapur/preceda-design-system/react';
<TextArea
ref={composerRef}
aria-label="Instruct the associate"
placeholder="Ask a question or instruct the associate…"
rows={1}
maxRows={8}
value={value}
onChange={(e) => setValue(e.target.value)}
onSubmitShortcut={() => canSend && send()}
disabled={sending}
/>
04
Search field
Search the record with one line. A glyph says what it is, a shortcut says how to reach it, and one status line says what came back.
Anatomy
.preceda-search
The line: search glyph at the start, the field, and the end slot.
.preceda-search__shortcut
A <kbd> hint (“/”) shown while the field is empty; hidden from assistive technology (the shortcut is documented in the shortcuts sheet).
Clear act
IconButton “Clear search” replaces the shortcut once there is text; Escape also clears.
.preceda-search__status
role="status": “Searching…” with the working point, the count, or the failure. Reserve it with status="" to keep the layout still.
--lg
The front-desk console: 48px, the reading serif at 17px.
Variants
Console (interactive)
Type three letters; Escape or the cross clears.
Paper
/
Lamp
/
In a pane
Paper
3 places · paragraphs 7, 11, 12
Lamp
3 places · paragraphs 7, 11, 12
State matrix
StatePaperLamp
empty
/
/
hover
/
/
focus-visible
loading
Searching…
Searching…
results
412 judgments · sorted by relevance
412 judgments · sorted by relevance
empty result
Nothing in the corpus matches. Check the citation or search by party name.
Nothing in the corpus matches. Check the citation or search by party name.
error
Search is unavailable for a moment. Try again.
Search is unavailable for a moment. Try again.
disabled
At 390 px
Full width; the shortcut hint is dropped on touch (there is no “/” key to reach). The status line holds its height so results do not jump as it changes.
390 px
Accessibility
type="search" gives the searchbox role and the platform clear-on-Escape; the native cancel glyph is hidden in favour of the labelled cross.
Status changes are polite live announcements (“412 judgments”), never alerts.
The shortcut is a hint only; the page must register the key and must not steal it while another field has focus.
Do
Say what can be searched in the placeholder.
Report zero results with a next step.
Don’t
Put a Search button beside a field that searches as you type.
The platform’s own list, given a ruled face. The native control keeps the keyboard, the phone’s wheel and the screen reader; the package draws the field and one chevron.
Anatomy
.preceda-select
Wrapper that positions the chevron; takes the quiet modifier.
.preceda-select__control
The <select> with appearance: none: the field face, 40px, Inter 14, room for the chevron.
.preceda-select__chevron
chevron-down icon in secondary ink; pointer-events: none.
--quiet
A bare word and chevron for running chrome: “Sort: Relevance”, “Desk ▾”.
Variants
Default
Paper
Where the application will be filed.
Lamp
Where the application will be filed.
Quiet
For a sort or a view switch inside chrome.
Paper
Lamp
Grouped options
Paper
Lamp
State matrix
StatePaperLamp
default
hover
focus-visible
error
Choose the court the application goes to.
Choose the court the application goes to.
disabled
At 390 px
The phone opens its own picker; nothing to build. The control grows to 44px and 17px text so iOS does not zoom.
390 px
Accessibility
Always native: no custom listbox for a closed set of choices. Use Combobox only when the set is searched.
Label with a visible <label> or aria-label; the error sets aria-invalid and aria-describedby.
Disabled options stay listed so counsel can see what exists but does not apply.
Do
Use for five to fifteen known choices.
Put a “Choose a …” first option when there is no sensible default.
Don’t
Use for two options; use Segmented or radios.
Restyle the open list; it belongs to the platform.
import { Switch } from '@luvkapur/preceda-design-system/react';
<Switch label="Lamp after 7 pm" checked={auto} onCheckedChange={setAuto} className="preceda-switch--row" />
08
Combobox
A field that suggests from the record: judges, counsel, police stations, acts. Focus never leaves the field; the list hangs beneath it on a raised sheet and the active suggestion carries a binding rule.
Anatomy
input[role="combobox"]
The field (the .preceda-field face) with aria-autocomplete="list", aria-expanded, aria-controls and aria-activedescendant.
.preceda-combobox__indicator
Chevron (turned while open), or the working point while suggestions load.
.preceda-combobox__listbox
role="listbox" on paper-raised with the sheet shadow, 240px before it scrolls; layer: popover.
.preceda-combobox__option
role="option": the label in Inter, one meta line in tertiary; aria-selected (active) draws the wash and a binding start rule; the value already set carries a tick.
.preceda-combobox__message
“Searching…” or “No matches found”, inside the list.
.preceda-combobox__live
A polite status: “4 suggestions. Use the arrow keys to choose.”
Variants
Judge (interactive)
Try “Del”, “Iyer” or “Saket”.
Paper
No matches found
Two letters to start. Arrow keys to choose; Enter to set.
Lamp
No matches found
Two letters to start. Arrow keys to choose; Enter to set.
State matrix
StatePaperLamp
closed
Chandramauli Kr. PrasadSupreme Court of India · 1,204 judgments
Pinaki Chandra GhoseSupreme Court of India · 986 judgments
Meera S. IyerDelhi High Court · 2,311 judgments
Arvind K. MenonDelhi High Court · 1,477 judgments
Sunita RaoDelhi High Court · 902 judgments
Additional Sessions Judge-03, SouthCourt of Sessions, Saket · 318 orders
Chandramauli Kr. PrasadSupreme Court of India · 1,204 judgments
Pinaki Chandra GhoseSupreme Court of India · 986 judgments
Meera S. IyerDelhi High Court · 2,311 judgments
Arvind K. MenonDelhi High Court · 1,477 judgments
Sunita RaoDelhi High Court · 902 judgments
Additional Sessions Judge-03, SouthCourt of Sessions, Saket · 318 orders
open
Meera S. IyerDelhi High Court · 2,311 judgments
Arvind K. MenonDelhi High Court · 1,477 judgments
Sunita RaoDelhi High Court · 902 judgments
3 suggestions. Use the arrow keys to choose.
Meera S. IyerDelhi High Court · 2,311 judgments
Arvind K. MenonDelhi High Court · 1,477 judgments
Sunita RaoDelhi High Court · 902 judgments
3 suggestions. Use the arrow keys to choose.
active option
Meera S. IyerDelhi High Court · 2,311 judgments
Arvind K. MenonDelhi High Court · 1,477 judgments
Sunita RaoDelhi High Court · 902 judgments
3 suggestions. Use the arrow keys to choose.
Meera S. IyerDelhi High Court · 2,311 judgments
Arvind K. MenonDelhi High Court · 1,477 judgments
Sunita RaoDelhi High Court · 902 judgments
3 suggestions. Use the arrow keys to choose.
loading
Searching…
Searching…
Searching…
Searching…
empty
No matches found
No matches found
No matches found
No matches found
error
No matches found
Suggestions are unavailable; type the full name.
No matches found
Suggestions are unavailable; type the full name.
disabled
No matches found
No matches found
At 390 px
The list stays anchored under the field and scrolls inside itself (overscroll contained) so the page does not move under the thumb. Each suggestion is 44px on touch. Inside a bottom sheet, keep the field above the keyboard.
390 px
Chandramauli Kr. PrasadSupreme Court of India · 1,204 judgments
Pinaki Chandra GhoseSupreme Court of India · 986 judgments
Meera S. IyerDelhi High Court · 2,311 judgments
3 suggestions. Use the arrow keys to choose.
Accessibility
WAI-ARIA 1.2 combobox, list autocomplete without automatic selection: DOM focus stays in the input; aria-activedescendant names the active option.
ArrowDown opens and moves to the first suggestion (Alt+ArrowDown opens only); ArrowUp opens at the last; Enter sets the active suggestion; Escape closes, and a second Escape clears; Tab closes and leaves.
Pointer: mousedown on an option is prevented so the field keeps focus; hovering moves the active option.
Counts and “No matches found” are announced politely; the tick on the current value has the text “current”.
Do
Let the product fetch and debounce; pass what came back as options with a meta line that tells two similar names apart.
Keep what counsel typed if they leave without choosing.
Don’t
Use for a short closed list; use Select.
Auto-select the first suggestion on Enter when none is active.
Attaching is a word, not a paperclip in a bubble. The act says what to attach; attached files are named on one line with their state in words; dropping a file anywhere on the composer works too.
Anatomy
.preceda-file-attach
The act (“Attach”, an underlined text button) and its hint (“FIR, orders, correspondence · PDF, DOCX”) in the small role; a hidden file input.
.preceda-attached
The line: “Attached:” then each file between middots.
__name
The file name in ink (a button when the finished file can be opened on the desk); truncates past 192px with the full name as a tooltip.
__detail / __working / __error
Size or length; the working point with “uploading”; the reason in binding ink, announced as an alert.
__remove
A small labelled cross (“Remove FIR.pdf”); disabled while a removal or turn is in flight.
.preceda-dropzone
Wraps the composer. While a file is held over it: a dashed binding rule and “Drop to attach to this matter”.
--panel
A standing drop place for matter creation: dashed rule-strong, a serif line and the Attach act.
Variants
Composer (interactive)
Choose files or drop them on the box; remove with the cross.
Paper
Ask a question or instruct the associate…
Attached
412 KB
FIR, orders, correspondence · PDF, DOCX
Drop to attach to this matter
Lamp
Ask a question or instruct the associate…
Attached
412 KB
FIR, orders, correspondence · PDF, DOCX
Drop to attach to this matter
Attached line
Paper
Attached
412 KB
Order 12 Aug.pdfuploading
Passport scan.heicnot a PDF, DOCX or TXT
Lamp
Attached
412 KB
Order 12 Aug.pdfuploading
Passport scan.heicnot a PDF, DOCX or TXT
Panel
Before a matter exists (the front desk, /matters).
Paper
Drop the FIR, orders or correspondence here
PDF, DOCX, TXT · 30 MB each
Lamp
Drop the FIR, orders or correspondence here
PDF, DOCX, TXT · 30 MB each
State matrix
StatePaperLamp
act · default
FIR, orders, correspondence · PDF, DOCX
FIR, orders, correspondence · PDF, DOCX
act · hover
FIR, orders, correspondence · PDF, DOCX
FIR, orders, correspondence · PDF, DOCX
act · focus-visible
FIR, orders, correspondence · PDF, DOCX
FIR, orders, correspondence · PDF, DOCX
act · disabled
Attach again when the associate replies
Attach again when the associate replies
uploading
Attached
Order 12 Aug.pdfuploading
Attached
Order 12 Aug.pdfuploading
attached
Attached
412 KB
88 KB
Attached
412 KB
88 KB
error
Attached
Bundle.ziplarger than 30 MB
Attached
Bundle.ziplarger than 30 MB
remove disabled
Attached
FIR.pdf412 KB
Attached
FIR.pdf412 KB
dragging
Ask a question or instruct the associate…
Drop to attach to this matter
Ask a question or instruct the associate…
Drop to attach to this matter
panel · dragging
Drop the FIR, orders or correspondence here
Drop the FIR, orders or correspondence here
At 390 px
There is no drag on a phone: the Attach act opens the system picker (Files, Photos, Camera). The attached line wraps under the composer; names truncate before the cross so the remove target never moves off the line.
390 px
Attached
FIR 214-2026 PS Saket.pdf412 KB
Order 12 Aug.pdfuploading
Passport scan.heicnot a PDF, DOCX or TXT
PDF, DOCX
Accessibility
The act is a real <button>; the hidden input has its own name (“Attach files”). Dropping is never the only way in.
Upload state is in words (“uploading”, the reason for a failure); failures are role="alert", progress is role="status".
Each remove act is named for its file. After a removal the product returns focus to the Attach act.
The drop overlay is aria-hidden: it repeats what the act already says.
Do
Say what belongs here in the hint (FIR, orders, correspondence) and the limits.
Name the reason a file failed in counsel’s words.
Don’t
Render files as chips or pills.
Start a turn per file; files queue for the next Send.
A recorded fact counsel can correct where it stands. At rest it reads as the record; under the hand a rule and the pen say it can change. Enter keeps the change, Escape restores it.
Anatomy
.preceda-inline-edit
Label | value grid (label column 120px), like a ledger row.
__label
Small-caps label role in secondary ink.
__value
A <button> showing the value in the serif (or the placeholder in tertiary italic); hover and focus draw a bottom rule and the edit glyph.
__input
The editing field: a bottom rule in ink, same serif and size, so nothing jumps.
__meta
One line of context from the record under the value (the judge’s bench, a counsel’s practice).
__status
“Saving…” with the working point, or the reason it failed in binding ink.
--title / --stacked
A heading renamed in place (matter title, draft name); label above value for narrow columns.
Variants
Ledger rows (interactive)
Click a value, type, press Enter or Escape. The police station must start “PS”.
Paper
Judge
Court of Sessions, Saket · 318 orders · bail granted in 61%
Opposing counsel
Police station
Lamp
Judge
Court of Sessions, Saket · 318 orders · bail granted in 61%
Opposing counsel
Police station
Title
Paper
Lamp
Stacked
Paper
Forum
Lamp
Forum
State matrix
StatePaperLamp
empty
Opposing counsel
Opposing counsel
filled
Judge
Judge
hover
Judge
Judge
focus-visible
Judge
Judge
editing
Police station
Police station
saving
Police station
Saving…
Police station
Saving…
error
Police station
Name the station as “PS …”, as the FIR does.
Police station
Name the station as “PS …”, as the FIR does.
with meta
Judge
Court of Sessions, Saket · 318 orders · bail granted in 61%
Judge
Court of Sessions, Saket · 318 orders · bail granted in 61%
meta loading
Judge
Reading the record…
Judge
Reading the record…
At 390 px
Below 390px use stacked (label above value). On touch the pen is always shown, because there is no hover to reveal it, and the field is set at 17px so iOS does not zoom.
390 px
Judge
Opposing counsel
Accessibility
At rest the value is a button named “Judge Additional Sessions Judge-03, South, edit”; activating it moves focus into the field with the text selected.
Enter saves, Escape restores the recorded value; leaving the field saves. Focus returns to the value afterwards.
Saving sets aria-busy on the field; a failure keeps the editor open, sets aria-invalid and is announced as status.
For suggestions, pass renderEditor and spread its inputProps onto a Combobox so the keys and name survive.
Do
Use for single recorded facts: judge, forum, opposing counsel, the matter title.
Show where a suggestion came from in the meta line.
Don’t
Use for anything that needs review before it counts (use a form with a Save act).
One of a few settings, applied at once. By default it is typographic — the words between middots, the chosen one in ink over a binding rule — so the theme switch reads like the account page: “Paper · Lamp”.
Anatomy
.preceda-segmented
role="radiogroup" with an accessible name; __label shows it before the options.
__option
role="radio" buttons; one tab stop (the checked one). Middots between options are drawn, not text.
[data-line-start]
Set by the component on the first option of each wrapped line; its middot is dropped, so no line opens with one.
__text
The word; aria-checked="true" puts it in ink over a 1px binding rule.
--ui
The same in small Inter, for the masthead account line and toolbars.
--ruled
Boxed segments for dense tool rows; the chosen segment is set in ink with paper text.
Variants
Paper · Lamp (interactive)
Arrow keys move and apply; the sample below changes its lighting.
Paper
Lighting
No notice under Section 35(3) BNSS was served on the Applicant.
Lamp
Lighting
No notice under Section 35(3) BNSS was served on the Applicant.
Chrome size
Paper
Lamp
Ruled
A sort switch above a register.
Paper
Lamp
State matrix
StatePaperLamp
default
hover
focus-visible
wrapped
disabled option
At 390 px
Options grow to 44px targets with a wider gap. Keep to two or three short words; past that, use a Select.
390 px
Lighting
Accessibility
WAI-ARIA radio group: Tab reaches the checked option; arrows move and select; Home and End jump.
The chosen option is said by aria-checked and drawn with a rule under it as well as ink, so it does not rest on colour.
Name the group (“Lighting”); show the name with showLabel when context does not make it obvious.
Do
Apply the choice immediately (theme, sort, view).
Use the typographic form in chrome and settings; the ruled form in tool rows.
Don’t
Use for navigation between pages; use Tabs or links.
Use icons without words (sun/moon) for Paper and Lamp.