Styling contract
Style tng-form-field through host CSS variables and your own classes on projected prefix, suffix, and action elements.
Supported contract
The public styling path is the host token contract inherited from the shared input shell. Apply these vars on a class attached to <tng-form-field>.
Public host contract
.docs-form-field-shell {
--tng-input-bg: var(--tng-semantic-background-surface);
--tng-input-border: var(--tng-semantic-border-subtle);
--tng-input-fg: var(--tng-semantic-foreground-primary);
--tng-input-radius: 0.85rem;
--tng-input-min-height: 2.75rem;
--tng-input-px: 0.9rem;
--tng-input-gap: 0.65rem;
--tng-input-focus-ring: color-mix(in srgb, var(--tng-semantic-focus-ring) 24%, transparent);
--tng-input-font-size: 0.96rem;
--tng-input-line-height: 1.45;
--tng-input-placeholder: var(--tng-semantic-foreground-muted);
}
Shell state ownership
The wrapper consumes the focus and validation states internally. If you need custom shell selectors keyed off data-focused or data-invalid, move to the headless <tng-input-group> primitive.
State ownership
/* <tng-form-field> exposes host tokens. */
/* Focus, invalid, disabled, and readonly attrs still live on the inner primitive group. */
/* If you need custom shell selectors keyed off those attrs, move to headless input-group. */
<tng-input-group class="docs-search-group">
<span tngPrefix aria-hidden="true">Search</span>
<input tngInput type="search" />
</tng-input-group>
.docs-search-group[data-focused] {
box-shadow: 0 0 0 3px color-mix(in srgb, var(--tng-semantic-focus-ring) 24%, transparent);
}
Workspace slug shell
Workspace slug shell
A projected suffix is often the reason to reach for form-field instead of the simple input component.
Workspace slug shell (Plain-CSS)
Workspace slug shell (Tailwind CSS)
Projected content classes
Projected content classes
Theme the wrapper at the host, then style projected prefix, suffix, and action elements with your own classes.
Projected content classes
<div class="docs-search-shell">
<tng-form-field>
<span tngPrefix class="docs-search-prefix" aria-hidden="true">
<tng-icon icon="search"></tng-icon>
</span>
<input tngInput type="search" placeholder="Search docs" />
<button tngSuffix type="button" class="docs-search-action">Clear</button>
</tng-form-field>
</div>
.docs-search-shell {
--tng-input-border: var(--tng-semantic-border-subtle);
--tng-input-radius: 0.85rem;
}
.docs-search-prefix { color: var(--tng-semantic-foreground-secondary); }
.docs-search-action { color: var(--tng-semantic-foreground-secondary); }
Headless escalation for shell state
The component wrapper keeps state selectors inside the primitive. Drop to headless input-group when you need custom focus or invalid selectors on the shell itself.
Headless escalation for shell state
/* <tng-form-field> exposes host tokens. */
/* Focus, invalid, disabled, and readonly attrs still live on the inner primitive group. */
/* If you need custom shell selectors keyed off those attrs, move to headless input-group. */
<tng-input-group class="docs-search-group">
<span tngPrefix aria-hidden="true">Search</span>
<input tngInput type="search" />
</tng-input-group>
.docs-search-group[data-focused] {
box-shadow: 0 0 0 3px color-mix(in srgb, var(--tng-semantic-focus-ring) 24%, transparent);
}