Download Latest Version v0.110.2 source code.zip (2.5 MB)
Email in envelope

Get an email when there's a new version of carbon-components-svelte

Home / v0.109.0
Name Modified Size InfoDownloads / Week
Parent folder
README.md 2026-06-15 47.9 kB
v0.109.0 source code.tar.gz 2026-06-15 1.2 MB
v0.109.0 source code.zip 2026-06-15 2.2 MB
Totals: 3 Items   3.4 MB 0

This release extends fluid forms across the input stack, adds new layout and input primitives, ships tabs and content-switcher variants, strengthens DataTable filtering and row-state tooling, surfaces dismissal reasons on overlay close events, improves UI Shell responsive navigation, lands accessibility fixes in tables, menus, and forms, cuts listener overhead with open-state gating on virtualized menus, and trims the CSS bundle ~7% by aligning with the Svelte 5 browser baseline.

173 changes in this release:

Category Count
Breaking changes 2
Features 91
Bug fixes 65
Performance 15

Full Changelog: https://github.com/carbon-design-system/carbon-components-svelte/compare/v0.108.1...v0.109.0


Fluid form support across inputs

Most list-box and text-based inputs now support the fluid variant for full-width, label-embedded forms. Set fluid on the control, or wrap fields in FluidForm. Each fluid control has a matching Fluid*Skeleton for loading states.

Works on TextInput, TextArea, NumberInput, Select, Dropdown, ComboBox, MultiSelect, DatePicker, TimePicker, Search, CopyInput, and PinCodeInput.

:::svelte
<script>
  import { FluidForm, TextInput, Dropdown } from "carbon-components-svelte";
</script>

<FluidForm>
  <TextInput fluid labelText="Application name" placeholder="customer-portal" />
  <Dropdown
    fluid
    labelText="Region"
    selectedId="us-east"
    items={[
      { id: "us-east", text: "US East" },
      { id: "eu-de", text: "EU Germany" },
    ]}
  />
</FluidForm>

fluid-form


PinCodeInput: segmented verification codes

New component for OTP and MFA flows. Segments advance on input, support paste across the row, and emit change, complete, clear, and paste events. Supports numeric and alphanumeric modes, masking, xs size, fluid layout, and skeleton states.

See the PinCodeInput docs.

:::svelte
<script>
  import { PinCodeInput } from "carbon-components-svelte";
</script>

<PinCodeInput
  count={6}
  labelText="Verification code"
  on:complete={(e) => console.log("complete", e.detail)}
/>

pin-code-input


CopyInput: read-only copyable values

New field for API tokens, endpoint URLs, and other labeled copy targets. Supports async copy, password obscuring with optional reveal, truncation, helper text, and the fluid variant. Prefetch on hover with on:mouseenter:copy-button.

See CopyInput async copy and fluid layout.

:::svelte
<script>
  import { CopyInput } from "carbon-components-svelte";

  let cachedToken = null;

  async function copyToken() {
    if (!cachedToken) {
      cachedToken = await fetchApiToken();
    }
    await navigator.clipboard.writeText(cachedToken);
  }
</script>

<CopyInput
  labelText="API token"
  type="password"
  value="sk-••••••••"
  copy={copyToken}
/>

copy-input


Text and Box: typography and layout primitives

Text wraps Carbon type styles (body-01, heading-03, expressive variants, color tokens) with optional maxWidth and truncation. Box provides token-driven spacing, borders, and width utilities. Truncate adds a lines prop for multi-line ellipsis.

See Text, Box, and Truncate multiline.

:::svelte
<script>
  import { Box, Text, Truncate } from "carbon-components-svelte";
</script>

<Box padding={5} border>
  <Text type="heading-03">Workspace settings</Text>
  <Truncate lines={2}>
    Long description text that clamps to two lines before showing an ellipsis.
  </Truncate>
</Box>

text


Tabs: dismissible and icon-only

dismissible renders a close button on each tab; handle on:dismiss to remove tabs from your data. Icon-only tabs show a tooltip from the label. The Tab default slot receives selected for conditional styling.

See dismissible tabs and icon-only tabs.

:::svelte
<script>
  import { Tab, Tabs } from "carbon-components-svelte";
  import Folder from "carbon-icons-svelte/lib/Folder.svelte";

  let tabs = [
    { id: "a", label: "Overview", icon: Folder },
    { id: "b", label: "Settings", icon: Folder },
  ];
</script>

<Tabs dismissible type="container" on:dismiss={(e) => {
  tabs = tabs.filter((tab) => tab.id !== e.detail.id);
}}>
  {#each tabs as tab (tab.id)}
    <Tab id={tab.id} label={tab.label} icon={tab.icon} />
  {/each}
</Tabs>

tabs-dismissible tabs-icon-only


DataTable: row state, sticky header, and filtering

Four related APIs for data-heavy UIs:

  • filterMode="hide" keeps non-matching rows mounted (hidden with CSS) so in-row inputs and menus keep state. No effect when pageSize or virtualization is enabled.
  • highlightedRowIds visually marks rows (e.g. while an overflow menu is open).
  • stickyHeaderMaxHeight caps the scrollable body under a sticky header (number = px, or a CSS length string).
  • refreshRow(id) / refreshCells() re-derive cell display after in-place row edits without replacing the rows array.

See filtering strategy, highlighted row, sticky max height, and editable cells.

:::svelte
<script>
  import { DataTable, Toolbar, ToolbarContent, ToolbarSearch } from "carbon-components-svelte";

  let table;
  let searchValue = "";
  let rows = [{ id: "1", name: "Alpha", note: "" }];
</script>

<DataTable
  bind:this={table}
  stickyHeader
  stickyHeaderMaxHeight="20rem"
  filterMode="hide"
  headers={[{ key: "name", value: "Name" }, { key: "note", value: "Note" }]}
  {rows}
>
  <Toolbar>
    <ToolbarContent>
      <ToolbarSearch bind:value={searchValue} />
    </ToolbarContent>
  </Toolbar>
</DataTable>

sticky-header-custom-max-height editable-table-state


close events with dismissal trigger

Overlays and menus now surface why they closed. Listen for on:close and read e.detail.trigger:

  • List boxes: "selection", "outside-click", "escape-key", "blur", "toggle"
  • Modals: "escape-key", "outside-click", "close-button", "programmatic"
  • Overflow menu: cancelable close before open flips

Applies to ComboBox, Dropdown, MultiSelect, OverflowMenu, ContextMenu, DatePicker, Popover, and UI Shell (HeaderAction, HeaderNavMenu, HeaderSearch).

:::svelte
<Dropdown
  labelText="Status"
  items={items}
  on:close={(e) => {
    if (e.detail.trigger === "outside-click") saveDraft();
  }}
/>

Modal and ComposedModal: fullWidth and programmatic close

fullWidth removes body padding so tables and fluid forms span edge to edge. Close events include trigger: "programmatic" when you call the close handler from code. Both variants dispatch a cancelable close event — call e.preventDefault() to keep the dialog open.

See Modal full width and prevent default close.

:::svelte
<script>
  import { ComposedModal, ModalBody, ModalHeader } from "carbon-components-svelte";

  let open = true;
</script>

<ComposedModal
  bind:open
  fullWidth
  on:close={(e) => {
    if (e.detail.trigger === "outside-click") e.preventDefault();
  }}
>
  <ModalHeader title="Audit log" />
  <ModalBody><!-- table or fluid form --></ModalBody>
</ComposedModal>

modal-fluid-width


UI Shell: responsive header nav and badges

HeaderSideNavItems duplicates header navigation links into the side nav below the large breakpoint (66rem), separated from regular side nav items with a divider. HeaderGlobalAction and icon-only Button support a badge slot for composing BadgeIndicator (notification dots and counts).

See HeaderSideNavItems and BadgeIndicator in UI Shell.

:::svelte
<script>
  import {
    BadgeIndicator,
    Header,
    HeaderGlobalAction,
    HeaderNav,
    HeaderNavItem,
    HeaderSideNavItems,
    SideNav,
    SideNavItems,
  } from "carbon-components-svelte";
  import Notification from "carbon-icons-svelte/lib/Notification.svelte";
</script>

<Header>
  <HeaderNav>
    <HeaderNavItem href="/reports" text="Reports" />
  </HeaderNav>
  <HeaderGlobalAction aria-label="Notifications">
    <svelte:fragment slot="badge">
      <BadgeIndicator count={3} />
    </svelte:fragment>
    <Notification size={20} />
  </HeaderGlobalAction>
</Header>

<SideNav>
  <SideNavItems>
    <HeaderSideNavItems>
      <HeaderNavItem href="/reports" text="Reports" />
    </HeaderSideNavItems>
  </SideNavItems>
</SideNav>

ui-shell-header-nav ui-shell-badge


ContentSwitcher: icon-only and low contrast

Switch supports an icon-only variant for compact toolbars. Low contrast styling softens the control for secondary contexts. Combine both for dense, muted toggle groups.

See icon-only and low contrast.

:::svelte
<script>
  import { ContentSwitcher, Switch } from "carbon-components-svelte";
  import Grid from "carbon-icons-svelte/lib/Grid.svelte";
  import List from "carbon-icons-svelte/lib/List.svelte";
</script>

<ContentSwitcher size="sm" lowContrast>
  <Switch icon={Grid} text="Grid" />
  <Switch icon={List} text="List" />
</ContentSwitcher>

content-switcher-icon-only content-switcher-low-contrast-icon-only content-switcher-low-contrast


List-box slot context: selected and highlighted

Customize item rendering in ComboBox, Dropdown, and MultiSelect without re-deriving selection state. The default slot exposes let:item, let:index, let:selected, and let:highlighted.

:::svelte
<ComboBox labelText="Contact" items={items} let:item let:selected let:highlighted>
  <span class:bx--list-box__menu-item__selected={selected}>
    {item.text}
    {#if highlighted}<span class="sr-only">, highlighted</span>{/if}
  </span>
</ComboBox>

Performance: open-state listener gating

Dismiss handlers no longer register window listeners for every closed menu on the page. Components attach outside-click, Escape, drag, and hover listeners only while open. A shared dismiss utility pools listeners by event type and options.

  • ComboBox, Dropdown, MultiSelect, OverflowMenu, Popover: outside-click only while open
  • Context menu: outside-click, Escape, and submenu hover gated on open state
  • Date picker: outside-click only while calendar is open; caches top-layer ancestor
  • Slider / RangeSlider: drag listeners only while dragging
  • Tooltips, UI Shell header: Escape and outside-interaction gated on open state

xs size on compact controls

Several form and chrome components now support size="xs" for dense toolbars, tables, and utility panels. Pair Toolbar and Pagination at xs with a compact DataTable, or shrink individual fields where horizontal space is tight.

Works on Search, TextInput, Select, PasswordInput, PinCodeInput, Pagination, Toolbar, and OverflowMenu.

:::svelte
<script>
  import {
    OverflowMenu,
    OverflowMenuItem,
    Pagination,
    Search,
    TextInput,
    Toolbar,
    ToolbarContent,
  } from "carbon-components-svelte";
</script>

<Toolbar size="xs">
  <ToolbarContent>
    <Search size="xs" placeholder="Filter rows..." />
    <TextInput size="xs" hideLabel labelText="Status" placeholder="Any" />
    <OverflowMenu size="xs" flipped>
      <OverflowMenuItem text="Export" />
    </OverflowMenu>
  </ToolbarContent>
</Toolbar>

<Pagination size="xs" totalItems={102} pageSizes={[10, 20, 50]} />

xs-compact-toolbar


StructuredList: multiple selection

Structured lists now support selecting more than one row. Set multiple on StructuredList and bind selected to an array of row values instead of a single string.

See StructuredList selection.

:::svelte
<script>
  import {
    StructuredList,
    StructuredListBody,
    StructuredListCell,
    StructuredListHead,
    StructuredListInput,
    StructuredListRow,
  } from "carbon-components-svelte";

  let selected = ["postgresql-value", "redis-value"];
</script>

<StructuredList selection multiple bind:selected>
  <StructuredListHead>
    <StructuredListRow head>
      <StructuredListCell head>Name</StructuredListCell>
      <StructuredListCell head>Type</StructuredListCell>
      <StructuredListCell head>{""}</StructuredListCell>
    </StructuredListRow>
  </StructuredListHead>
  <StructuredListBody>
    <StructuredListRow label for="postgresql">
      <StructuredListCell>PostgreSQL</StructuredListCell>
      <StructuredListCell>Relational</StructuredListCell>
      <StructuredListInput id="postgresql" value="postgresql-value" title="PostgreSQL" name="database" />
      <StructuredListCell />
    </StructuredListRow>
    <!-- additional rows -->
  </StructuredListBody>
</StructuredList>

structured-list-multi


BadgeIndicator: notification dots and counts

New BadgeIndicator component for unread activity on icon-only buttons. Omit count for a presence dot, pass a number for a capped badge (999+), or pass a string to control the label yourself. Compose it through the badge slot on Button or HeaderGlobalAction.

See the BadgeIndicator docs and count variants.

:::svelte
<script>
  import { BadgeIndicator, Button } from "carbon-components-svelte";
  import Notification from "carbon-icons-svelte/lib/Notification.svelte";
</script>

<Button kind="ghost" icon={Notification} iconDescription="Notifications">
  <BadgeIndicator slot="badge" count={4} />
</Button>

badge-indicator


More in this release

  • Local/session storage: sync={false} opts out of cross-tab storage events; object and array mutations now persist correctly

Breaking changes

AccordionItem: iconDescription renamed to ariaLabel

The heading button prop is now ariaLabel. The decorative chevron no longer carries its own aria-label. Search your codebase for iconDescription on AccordionItem and rename it.

CSS: Svelte 5 browser baseline (~7% smaller bundle)

Older browser targets are dropped to match the Svelte 5 baseline (#3235). :has() selectors are replaced with marker classes (#3256). Verify layouts in your supported browsers after upgrading.


What's Changed

Breaking Changes

Features

Bug Fixes

Performance

Source: README.md, updated 2026-06-15