Input group
An input paired with leading or trailing addons on one continuous surface.
Basic
Wrap an addon and a field component (.input, .select, or .textarea) in .input-group. The addon sits flush against the input on a shared surface, with a single focus state on the wrapper.
<div class="demo-stack" style="max-width: 24rem;">
<div class="input-group">
<span class="input-group__text">https://</span>
<input type="text" class="input" placeholder="example.com" />
</div>
<div class="input-group">
<input type="text" class="input" placeholder="yourname" />
<span class="input-group__text">@company.com</span>
</div>
</div>Icon
Drop an icon into .input-group__text for a leading or trailing glyph. The addon stays transparent so the icon reads against the wrapper.
<div style="max-width: 24rem;">
<div class="input-group">
<span class="input-group__text"><i data-lucide="search"></i></span>
<input type="search" class="input" placeholder="Search" />
</div>
</div>Sizes
Add .input-group--sm or .input-group--lg on the wrapper and the matching size modifier on the field child (e.g. .input--sm, .select--lg) to scale every member together.
<div class="demo-stack" style="max-width: 24rem;">
<div class="input-group input-group--sm">
<span class="input-group__text"><i data-lucide="at-sign"></i></span>
<input type="text" class="input input--sm" placeholder="Small" />
</div>
<div class="input-group">
<span class="input-group__text"><i data-lucide="at-sign"></i></span>
<input type="text" class="input" placeholder="Default" />
</div>
<div class="input-group input-group--lg">
<span class="input-group__text"><i data-lucide="at-sign"></i></span>
<input type="text" class="input input--lg" placeholder="Large" />
</div>
</div>With button
A button slot sits inset inside the wrapper with its own concentric pill shape. Reads as a chip floating in the field rather than chrome welded to its edge. Retune the inset with --input-group-inset.
<div class="demo-stack" style="max-width: 24rem;">
<div class="input-group">
<input type="search" class="input" placeholder="Search" />
<button type="button" class="btn btn--primary">Go</button>
</div>
<div class="input-group">
<button type="button" class="btn btn--outline btn--neutral">Copy</button>
<input type="text" class="input" value="https://stisla.dev/v3" readonly />
</div>
</div>Pair the button size with the wrapper size so the chip's text fits its chip. .input-group--sm + .btn--sm, default + default, .input-group--lg + .btn--lg.
<div class="demo-stack" style="max-width: 24rem;">
<div class="input-group input-group--sm">
<input type="search" class="input input--sm" placeholder="Small" />
<button type="button" class="btn btn--sm btn--primary">Go</button>
</div>
<div class="input-group">
<input type="search" class="input" placeholder="Default" />
<button type="button" class="btn btn--primary">Go</button>
</div>
<div class="input-group input-group--lg">
<input type="search" class="input input--lg" placeholder="Large" />
<button type="button" class="btn btn--lg btn--primary">Go</button>
</div>
</div>Select
A <select class="select"> stands in for the input. The wrapper strips its border the same way it does for .input.
<div style="max-width: 24rem;">
<div class="input-group">
<select class="select" aria-label="Currency" style="max-width: 5.5rem;">
<option selected>USD</option>
<option>EUR</option>
<option>GBP</option>
<option>JPY</option>
</select>
<input type="number" class="input" placeholder="Amount" />
</div>
</div>Labelled select
Lead with a text or icon addon and let the select stand in for the input. Reads as a labelled chooser, no separate field needed.
<div class="demo-stack" style="max-width: 24rem;">
<div class="input-group">
<label class="input-group__text" for="currencyOnly">Currency</label>
<select class="select" id="currencyOnly">
<option selected>USD</option>
<option>EUR</option>
<option>GBP</option>
<option>JPY</option>
</select>
</div>
<div class="input-group">
<span class="input-group__text"><i data-lucide="globe"></i></span>
<select class="select" aria-label="Language">
<option selected>English</option>
<option>Bahasa Indonesia</option>
<option>日本語</option>
<option>Deutsch</option>
</select>
</div>
</div>With select
Mix a text addon and a select on opposite sides for a labelled, scoped input.
<div style="max-width: 24rem;">
<div class="input-group">
<label class="input-group__text" for="amountCurrency">
Input group
An input paired with leading or trailing addons on one continuous surface.
Basic
Wrap an addon and a field component (.input, .select, or .textarea) in .input-group. The addon sits flush against the input on a shared surface, with a single focus state on the wrapper.
https://
@company.com
<div class="demo-stack" style="max-width: 24rem;">
<div class="input-group">
<span class="input-group__text">https://</span>
<input type="text" class="input" placeholder="example.com" />
</div>
<div class="input-group">
<input type="text" class="input" placeholder="yourname" />
<span class="input-group__text">@company.com</span>
</div>
</div>
Icon
Drop an icon into .input-group__text for a leading or trailing glyph. The addon stays transparent so the icon reads against the wrapper.
<div style="max-width: 24rem;">
<div class="input-group">
<span class="input-group__text"><i data-lucide="search"></i></span>
<input type="search" class="input" placeholder="Search" />
</div>
</div>
Sizes
Add .input-group--sm or .input-group--lg on the wrapper and the matching size modifier on the field child (e.g. .input--sm, .select--lg) to scale every member together.
<div class="demo-stack" style="max-width: 24rem;">
<div class="input-group input-group--sm">
<span class="input-group__text"><i data-lucide="at-sign"></i></span>
<input type="text" class="input input--sm" placeholder="Small" />
</div>
<div class="input-group">
<span class="input-group__text"><i data-lucide="at-sign"></i></span>
<input type="text" class="input" placeholder="Default" />
</div>
<div class="input-group input-group--lg">
<span class="input-group__text"><i data-lucide="at-sign"></i></span>
<input type="text" class="input input--lg" placeholder="Large" />
</div>
</div>
With button
A button slot sits inset inside the wrapper with its own concentric pill shape. Reads as a chip floating in the field rather than chrome welded to its edge. Retune the inset with --input-group-inset.
<div class="demo-stack" style="max-width: 24rem;">
<div class="input-group">
<input type="search" class="input" placeholder="Search" />
<button type="button" class="btn btn--primary">Go</button>
</div>
<div class="input-group">
<button type="button" class="btn btn--outline btn--neutral">Copy</button>
<input type="text" class="input" value="https://stisla.dev/v3" readonly />
</div>
</div>
Pair the button size with the wrapper size so the chip's text fits its chip. .input-group--sm + .btn--sm, default + default, .input-group--lg + .btn--lg.
<div class="demo-stack" style="max-width: 24rem;">
<div class="input-group input-group--sm">
<input type="search" class="input input--sm" placeholder="Small" />
<button type="button" class="btn btn--sm btn--primary">Go</button>
</div>
<div class="input-group">
<input type="search" class="input" placeholder="Default" />
<button type="button" class="btn btn--primary">Go</button>
</div>
<div class="input-group input-group--lg">
<input type="search" class="input input--lg" placeholder="Large" />
<button type="button" class="btn btn--lg btn--primary">Go</button>
</div>
</div>
Select
A <select class="select"> stands in for the input. The wrapper strips its border the same way it does for .input.
<div style="max-width: 24rem;">
<div class="input-group">
<select class="select" aria-label="Currency" style="max-width: 5.5rem;">
<option selected>USD</option>
<option>EUR</option>
<option>GBP</option>
<option>JPY</option>
</select>
<input type="number" class="input" placeholder="Amount" />
</div>
</div>
Labelled select
Lead with a text or icon addon and let the select stand in for the input. Reads as a labelled chooser, no separate field needed.
<div class="demo-stack" style="max-width: 24rem;">
<div class="input-group">
<label class="input-group__text" for="currencyOnly">Currency</label>
<select class="select" id="currencyOnly">
<option selected>USD</option>
<option>EUR</option>
<option>GBP</option>
<option>JPY</option>
</select>
</div>
<div class="input-group">
<span class="input-group__text"><i data-lucide="globe"></i></span>
<select class="select" aria-label="Language">
<option selected>English</option>
<option>Bahasa Indonesia</option>
<option>日本語</option>
<option>Deutsch</option>
</select>
</div>
</div>
With select
Mix a text addon and a select on opposite sides for a labelled, scoped input.
<div style="max-width: 24rem;">
<div class="input-group">
<label class="input-group__text" for="amountCurrency">$</label>
<input type="number" class="input" id="amountCurrency" placeholder="Amount" />
<select class="select" aria-label="Currency" style="max-width: 5.5rem;">
<option selected>USD</option>
<option>EUR</option>
<option>GBP</option>
<option>JPY</option>
</select>
</div>
</div>
Multiple addons
Stack more than one addon on the same side. They share the same surface and read as one phrase.
$
0.00
<div style="max-width: 24rem;">
<div class="input-group">
<span class="input-group__text">$</span>
<span class="input-group__text">0.00</span>
<input type="text" class="input" />
</div>
</div>
Textarea
A textarea grows past the default height and the wrapper grows with it. Addons hold to their top edge.
<div style="max-width: 24rem;">
<div class="input-group">
<span class="input-group__text"><i data-lucide="message-square"></i></span>
<textarea class="textarea" rows="3" placeholder="Leave a note"></textarea>
</div>
</div>
Validation
An invalid child paints the wrapper red. Set aria-invalid="true" for server-rendered errors, or pair required with :user-invalid for native browser validation after the first touch.
$
<div class="demo-stack" style="max-width: 24rem;">
<div class="input-group">
<span class="input-group__text"><i data-lucide="at-sign"></i></span>
<input type="email" class="input" value="not-an-email" aria-invalid="true" />
</div>
<div class="input-group">
<span class="input-group__text">$</span>
<input type="number" class="input" min="0" value="-5" aria-invalid="true" />
</div>
</div>
Disabled
Disable the input directly. The wrapper dims with the input via its opacity, with no extra class on the group.
https://
<div style="max-width: 24rem;">
<div class="input-group">
<span class="input-group__text">https://</span>
<input type="text" class="input" value="example.com" disabled />
</div>
</div>
Customization
Seven variables retune .input-group without touching component CSS. Override on .input-group itself, on a parent scope, or on :root. The cascade scopes the change.
Variable
Default
Use
--input-group-radius
var(--st-radius)
Wrapper corner radius (per-component override via --st-input-radius; sizes pull --st-radius-sm / -lg)
--input-group-height
calc(2.25rem * var(--st-density))
Wrapper height; sm and lg reassign this
--input-group-bg
var(--st-surface)
Wrapper background
--input-group-border
var(--st-border)
Wrapper border color
--input-group-padding-x
calc(0.625rem * var(--st-density))
Addon horizontal padding; matches the field child's padding-x at each size so an addon's text baseline aligns with the input's
--input-group-inset
calc(0.25rem * var(--st-density))
Margin around an inline .btn child. The button's height becomes wrapper height − 2 × inset and its radius becomes wrapper radius − inset for concentric corners
--input-group-addon-color
var(--st-muted-foreground)
Addon text and icon color
The wrapper owns the chrome. Child .input, .select, and .textarea elements clear their own background, border, and focus halo so only the wrapper's surface and focus state show.
#x3C;/label>
<input type="number" class="input" id="amountCurrency" placeholder="Amount" />
<select class="select" aria-label="Currency" style="max-width: 5.5rem;">
<option selected>USD</option>
<option>EUR</option>
<option>GBP</option>
<option>JPY</option>
</select>
</div>
</div>Multiple addons
Stack more than one addon on the same side. They share the same surface and read as one phrase.
<div style="max-width: 24rem;">
<div class="input-group">
<span class="input-group__text">
Input group
An input paired with leading or trailing addons on one continuous surface.
Basic
Wrap an addon and a field component (.input, .select, or .textarea) in .input-group. The addon sits flush against the input on a shared surface, with a single focus state on the wrapper.
https://
@company.com
<div class="demo-stack" style="max-width: 24rem;">
<div class="input-group">
<span class="input-group__text">https://</span>
<input type="text" class="input" placeholder="example.com" />
</div>
<div class="input-group">
<input type="text" class="input" placeholder="yourname" />
<span class="input-group__text">@company.com</span>
</div>
</div>
Icon
Drop an icon into .input-group__text for a leading or trailing glyph. The addon stays transparent so the icon reads against the wrapper.
<div style="max-width: 24rem;">
<div class="input-group">
<span class="input-group__text"><i data-lucide="search"></i></span>
<input type="search" class="input" placeholder="Search" />
</div>
</div>
Sizes
Add .input-group--sm or .input-group--lg on the wrapper and the matching size modifier on the field child (e.g. .input--sm, .select--lg) to scale every member together.
<div class="demo-stack" style="max-width: 24rem;">
<div class="input-group input-group--sm">
<span class="input-group__text"><i data-lucide="at-sign"></i></span>
<input type="text" class="input input--sm" placeholder="Small" />
</div>
<div class="input-group">
<span class="input-group__text"><i data-lucide="at-sign"></i></span>
<input type="text" class="input" placeholder="Default" />
</div>
<div class="input-group input-group--lg">
<span class="input-group__text"><i data-lucide="at-sign"></i></span>
<input type="text" class="input input--lg" placeholder="Large" />
</div>
</div>
With button
A button slot sits inset inside the wrapper with its own concentric pill shape. Reads as a chip floating in the field rather than chrome welded to its edge. Retune the inset with --input-group-inset.
<div class="demo-stack" style="max-width: 24rem;">
<div class="input-group">
<input type="search" class="input" placeholder="Search" />
<button type="button" class="btn btn--primary">Go</button>
</div>
<div class="input-group">
<button type="button" class="btn btn--outline btn--neutral">Copy</button>
<input type="text" class="input" value="https://stisla.dev/v3" readonly />
</div>
</div>
Pair the button size with the wrapper size so the chip's text fits its chip. .input-group--sm + .btn--sm, default + default, .input-group--lg + .btn--lg.
<div class="demo-stack" style="max-width: 24rem;">
<div class="input-group input-group--sm">
<input type="search" class="input input--sm" placeholder="Small" />
<button type="button" class="btn btn--sm btn--primary">Go</button>
</div>
<div class="input-group">
<input type="search" class="input" placeholder="Default" />
<button type="button" class="btn btn--primary">Go</button>
</div>
<div class="input-group input-group--lg">
<input type="search" class="input input--lg" placeholder="Large" />
<button type="button" class="btn btn--lg btn--primary">Go</button>
</div>
</div>
Select
A <select class="select"> stands in for the input. The wrapper strips its border the same way it does for .input.
<div style="max-width: 24rem;">
<div class="input-group">
<select class="select" aria-label="Currency" style="max-width: 5.5rem;">
<option selected>USD</option>
<option>EUR</option>
<option>GBP</option>
<option>JPY</option>
</select>
<input type="number" class="input" placeholder="Amount" />
</div>
</div>
Labelled select
Lead with a text or icon addon and let the select stand in for the input. Reads as a labelled chooser, no separate field needed.
<div class="demo-stack" style="max-width: 24rem;">
<div class="input-group">
<label class="input-group__text" for="currencyOnly">Currency</label>
<select class="select" id="currencyOnly">
<option selected>USD</option>
<option>EUR</option>
<option>GBP</option>
<option>JPY</option>
</select>
</div>
<div class="input-group">
<span class="input-group__text"><i data-lucide="globe"></i></span>
<select class="select" aria-label="Language">
<option selected>English</option>
<option>Bahasa Indonesia</option>
<option>日本語</option>
<option>Deutsch</option>
</select>
</div>
</div>
With select
Mix a text addon and a select on opposite sides for a labelled, scoped input.
<div style="max-width: 24rem;">
<div class="input-group">
<label class="input-group__text" for="amountCurrency">$</label>
<input type="number" class="input" id="amountCurrency" placeholder="Amount" />
<select class="select" aria-label="Currency" style="max-width: 5.5rem;">
<option selected>USD</option>
<option>EUR</option>
<option>GBP</option>
<option>JPY</option>
</select>
</div>
</div>
Multiple addons
Stack more than one addon on the same side. They share the same surface and read as one phrase.
$
0.00
<div style="max-width: 24rem;">
<div class="input-group">
<span class="input-group__text">$</span>
<span class="input-group__text">0.00</span>
<input type="text" class="input" />
</div>
</div>
Textarea
A textarea grows past the default height and the wrapper grows with it. Addons hold to their top edge.
<div style="max-width: 24rem;">
<div class="input-group">
<span class="input-group__text"><i data-lucide="message-square"></i></span>
<textarea class="textarea" rows="3" placeholder="Leave a note"></textarea>
</div>
</div>
Validation
An invalid child paints the wrapper red. Set aria-invalid="true" for server-rendered errors, or pair required with :user-invalid for native browser validation after the first touch.
$
<div class="demo-stack" style="max-width: 24rem;">
<div class="input-group">
<span class="input-group__text"><i data-lucide="at-sign"></i></span>
<input type="email" class="input" value="not-an-email" aria-invalid="true" />
</div>
<div class="input-group">
<span class="input-group__text">$</span>
<input type="number" class="input" min="0" value="-5" aria-invalid="true" />
</div>
</div>
Disabled
Disable the input directly. The wrapper dims with the input via its opacity, with no extra class on the group.
https://
<div style="max-width: 24rem;">
<div class="input-group">
<span class="input-group__text">https://</span>
<input type="text" class="input" value="example.com" disabled />
</div>
</div>
Customization
Seven variables retune .input-group without touching component CSS. Override on .input-group itself, on a parent scope, or on :root. The cascade scopes the change.
Variable
Default
Use
--input-group-radius
var(--st-radius)
Wrapper corner radius (per-component override via --st-input-radius; sizes pull --st-radius-sm / -lg)
--input-group-height
calc(2.25rem * var(--st-density))
Wrapper height; sm and lg reassign this
--input-group-bg
var(--st-surface)
Wrapper background
--input-group-border
var(--st-border)
Wrapper border color
--input-group-padding-x
calc(0.625rem * var(--st-density))
Addon horizontal padding; matches the field child's padding-x at each size so an addon's text baseline aligns with the input's
--input-group-inset
calc(0.25rem * var(--st-density))
Margin around an inline .btn child. The button's height becomes wrapper height − 2 × inset and its radius becomes wrapper radius − inset for concentric corners
--input-group-addon-color
var(--st-muted-foreground)
Addon text and icon color
The wrapper owns the chrome. Child .input, .select, and .textarea elements clear their own background, border, and focus halo so only the wrapper's surface and focus state show.
#x3C;/span>
<span class="input-group__text">0.00</span>
<input type="text" class="input" />
</div>
</div>Textarea
A textarea grows past the default height and the wrapper grows with it. Addons hold to their top edge.
<div style="max-width: 24rem;">
<div class="input-group">
<span class="input-group__text"><i data-lucide="message-square"></i></span>
<textarea class="textarea" rows="3" placeholder="Leave a note"></textarea>
</div>
</div>Validation
An invalid child paints the wrapper red. Set aria-invalid="true" for server-rendered errors, or pair required with :user-invalid for native browser validation after the first touch.
<div class="demo-stack" style="max-width: 24rem;">
<div class="input-group">
<span class="input-group__text"><i data-lucide="at-sign"></i></span>
<input type="email" class="input" value="not-an-email" aria-invalid="true" />
</div>
<div class="input-group">
<span class="input-group__text">
Input group
An input paired with leading or trailing addons on one continuous surface.
Basic
Wrap an addon and a field component (.input, .select, or .textarea) in .input-group. The addon sits flush against the input on a shared surface, with a single focus state on the wrapper.
https://
@company.com
<div class="demo-stack" style="max-width: 24rem;">
<div class="input-group">
<span class="input-group__text">https://</span>
<input type="text" class="input" placeholder="example.com" />
</div>
<div class="input-group">
<input type="text" class="input" placeholder="yourname" />
<span class="input-group__text">@company.com</span>
</div>
</div>
Icon
Drop an icon into .input-group__text for a leading or trailing glyph. The addon stays transparent so the icon reads against the wrapper.
<div style="max-width: 24rem;">
<div class="input-group">
<span class="input-group__text"><i data-lucide="search"></i></span>
<input type="search" class="input" placeholder="Search" />
</div>
</div>
Sizes
Add .input-group--sm or .input-group--lg on the wrapper and the matching size modifier on the field child (e.g. .input--sm, .select--lg) to scale every member together.
<div class="demo-stack" style="max-width: 24rem;">
<div class="input-group input-group--sm">
<span class="input-group__text"><i data-lucide="at-sign"></i></span>
<input type="text" class="input input--sm" placeholder="Small" />
</div>
<div class="input-group">
<span class="input-group__text"><i data-lucide="at-sign"></i></span>
<input type="text" class="input" placeholder="Default" />
</div>
<div class="input-group input-group--lg">
<span class="input-group__text"><i data-lucide="at-sign"></i></span>
<input type="text" class="input input--lg" placeholder="Large" />
</div>
</div>
With button
A button slot sits inset inside the wrapper with its own concentric pill shape. Reads as a chip floating in the field rather than chrome welded to its edge. Retune the inset with --input-group-inset.
<div class="demo-stack" style="max-width: 24rem;">
<div class="input-group">
<input type="search" class="input" placeholder="Search" />
<button type="button" class="btn btn--primary">Go</button>
</div>
<div class="input-group">
<button type="button" class="btn btn--outline btn--neutral">Copy</button>
<input type="text" class="input" value="https://stisla.dev/v3" readonly />
</div>
</div>
Pair the button size with the wrapper size so the chip's text fits its chip. .input-group--sm + .btn--sm, default + default, .input-group--lg + .btn--lg.
<div class="demo-stack" style="max-width: 24rem;">
<div class="input-group input-group--sm">
<input type="search" class="input input--sm" placeholder="Small" />
<button type="button" class="btn btn--sm btn--primary">Go</button>
</div>
<div class="input-group">
<input type="search" class="input" placeholder="Default" />
<button type="button" class="btn btn--primary">Go</button>
</div>
<div class="input-group input-group--lg">
<input type="search" class="input input--lg" placeholder="Large" />
<button type="button" class="btn btn--lg btn--primary">Go</button>
</div>
</div>
Select
A <select class="select"> stands in for the input. The wrapper strips its border the same way it does for .input.
<div style="max-width: 24rem;">
<div class="input-group">
<select class="select" aria-label="Currency" style="max-width: 5.5rem;">
<option selected>USD</option>
<option>EUR</option>
<option>GBP</option>
<option>JPY</option>
</select>
<input type="number" class="input" placeholder="Amount" />
</div>
</div>
Labelled select
Lead with a text or icon addon and let the select stand in for the input. Reads as a labelled chooser, no separate field needed.
<div class="demo-stack" style="max-width: 24rem;">
<div class="input-group">
<label class="input-group__text" for="currencyOnly">Currency</label>
<select class="select" id="currencyOnly">
<option selected>USD</option>
<option>EUR</option>
<option>GBP</option>
<option>JPY</option>
</select>
</div>
<div class="input-group">
<span class="input-group__text"><i data-lucide="globe"></i></span>
<select class="select" aria-label="Language">
<option selected>English</option>
<option>Bahasa Indonesia</option>
<option>日本語</option>
<option>Deutsch</option>
</select>
</div>
</div>
With select
Mix a text addon and a select on opposite sides for a labelled, scoped input.
<div style="max-width: 24rem;">
<div class="input-group">
<label class="input-group__text" for="amountCurrency">$</label>
<input type="number" class="input" id="amountCurrency" placeholder="Amount" />
<select class="select" aria-label="Currency" style="max-width: 5.5rem;">
<option selected>USD</option>
<option>EUR</option>
<option>GBP</option>
<option>JPY</option>
</select>
</div>
</div>
Multiple addons
Stack more than one addon on the same side. They share the same surface and read as one phrase.
$
0.00
<div style="max-width: 24rem;">
<div class="input-group">
<span class="input-group__text">$</span>
<span class="input-group__text">0.00</span>
<input type="text" class="input" />
</div>
</div>
Textarea
A textarea grows past the default height and the wrapper grows with it. Addons hold to their top edge.
<div style="max-width: 24rem;">
<div class="input-group">
<span class="input-group__text"><i data-lucide="message-square"></i></span>
<textarea class="textarea" rows="3" placeholder="Leave a note"></textarea>
</div>
</div>
Validation
An invalid child paints the wrapper red. Set aria-invalid="true" for server-rendered errors, or pair required with :user-invalid for native browser validation after the first touch.
$
<div class="demo-stack" style="max-width: 24rem;">
<div class="input-group">
<span class="input-group__text"><i data-lucide="at-sign"></i></span>
<input type="email" class="input" value="not-an-email" aria-invalid="true" />
</div>
<div class="input-group">
<span class="input-group__text">$</span>
<input type="number" class="input" min="0" value="-5" aria-invalid="true" />
</div>
</div>
Disabled
Disable the input directly. The wrapper dims with the input via its opacity, with no extra class on the group.
https://
<div style="max-width: 24rem;">
<div class="input-group">
<span class="input-group__text">https://</span>
<input type="text" class="input" value="example.com" disabled />
</div>
</div>
Customization
Seven variables retune .input-group without touching component CSS. Override on .input-group itself, on a parent scope, or on :root. The cascade scopes the change.
Variable
Default
Use
--input-group-radius
var(--st-radius)
Wrapper corner radius (per-component override via --st-input-radius; sizes pull --st-radius-sm / -lg)
--input-group-height
calc(2.25rem * var(--st-density))
Wrapper height; sm and lg reassign this
--input-group-bg
var(--st-surface)
Wrapper background
--input-group-border
var(--st-border)
Wrapper border color
--input-group-padding-x
calc(0.625rem * var(--st-density))
Addon horizontal padding; matches the field child's padding-x at each size so an addon's text baseline aligns with the input's
--input-group-inset
calc(0.25rem * var(--st-density))
Margin around an inline .btn child. The button's height becomes wrapper height − 2 × inset and its radius becomes wrapper radius − inset for concentric corners
--input-group-addon-color
var(--st-muted-foreground)
Addon text and icon color
The wrapper owns the chrome. Child .input, .select, and .textarea elements clear their own background, border, and focus halo so only the wrapper's surface and focus state show.
#x3C;/span>
<input type="number" class="input" min="0" value="-5" aria-invalid="true" />
</div>
</div>Disabled
Disable the input directly. The wrapper dims with the input via its opacity, with no extra class on the group.
<div style="max-width: 24rem;">
<div class="input-group">
<span class="input-group__text">https://</span>
<input type="text" class="input" value="example.com" disabled />
</div>
</div>Customization
Seven variables retune .input-group without touching component CSS. Override on .input-group itself, on a parent scope, or on :root. The cascade scopes the change.
| Variable | Default | Use |
|---|---|---|
--input-group-radius |
var(--st-radius) | Wrapper corner radius (per-component override via --st-input-radius; sizes pull --st-radius-sm / -lg) |
--input-group-height |
calc(2.25rem * var(--st-density)) | Wrapper height; sm and lg reassign this |
--input-group-bg |
var(--st-surface) | Wrapper background |
--input-group-border |
var(--st-border) | Wrapper border color |
--input-group-padding-x |
calc(0.625rem * var(--st-density)) | Addon horizontal padding; matches the field child's padding-x at each size so an addon's text baseline aligns with the input's |
--input-group-inset |
calc(0.25rem * var(--st-density)) | Margin around an inline .btn child. The button's height becomes wrapper height − 2 × inset and its radius becomes wrapper radius − inset for concentric corners |
--input-group-addon-color |
var(--st-muted-foreground) | Addon text and icon color |
The wrapper owns the chrome. Child .input, .select, and .textarea elements clear their own background, border, and focus halo so only the wrapper's surface and focus state show.