github carbon-design-system/carbon-components-svelte v0.111.0

4 hours ago

This release ships TreeView virtualization, lazy loading, and tri-state checkboxes; DataTable CSV export, footers, and column controls; leaner prebuilt theme CSS; selectable menus; slider marks; tab and accordion lazy panels; and 4 new components (LinkDownload, TableFoot, MenuItemGroup, MenuItemRadioGroup). Also in this release: a year picker on DatePicker, clearable dropdowns, modal loading/submit affordances, and accessibility fixes across tables, list boxes, sliders, and UI Shell.

149 changes in this release:

Category Count
New components 4
Breaking changes 5
Features 66
Bug fixes 64
Performance 14

Full Changelog: v0.110.2...v0.111.0


TreeView: virtualization, lazy loading, and checkboxes

TreeView can virtualize large trees, fetch children on expand via hasChildren + the childNodes slot, and render tri-state checkboxes with selectionMode="checkbox". Type-ahead search, getNode/getNodes accessors, and aria-level/posinset/setsize land in the same release.

See virtualization, lazy loading, and checkbox.

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

  let checkedIds = [3];
  const nodes = [
    {
      id: 1,
      text: "Analytics",
      nodes: [
        { id: 3, text: "Apache Spark" },
        { id: 4, text: "Hadoop" },
      ],
    },
    { id: 7, text: "Blockchain", hasChildren: true },
  ];
</script>

<TreeView
  selectionMode="checkbox"
  labelText="Cloud Products"
  {nodes}
  bind:checkedIds
  virtualize
/>
TreeView checkboxes
tree-view-virtual.mov

DataTable: footer, CSV export, hidden columns, and shift+click

Summary rows via the footerCell slot (and exported TableFoot). Serialize the current view with toCsv, then download with LinkDownload or downloadFile. Hide columns with columnHidden without dropping them from headers. Align numeric columns with columnAlign: "end". Hold Shift while clicking a selectable checkbox to select a range.

See footer, export, column visibility, and alignment.

<script>
  import { DataTable, LinkDownload, toCsv } from "carbon-components-svelte";

  const headers = [
    { key: "name", value: "Name" },
    { key: "requests", value: "Requests", columnAlign: "end" },
    { key: "rule", value: "Rule", columnHidden: true },
  ];
  const rows = [
    { id: "a", name: "Load Balancer 3", requests: 12480, rule: "Round robin" },
    { id: "b", name: "Load Balancer 1", requests: 8112, rule: "DNS delegation" },
  ];
  const totalRequests = rows.reduce((total, row) => total + row.requests, 0);
</script>

<DataTable selectable {headers} {rows}>
  <svelte:fragment slot="footerCell" let:header let:index>
    {#if header.key === "requests"}
      {totalRequests.toLocaleString()}
    {:else if index === 0}
      Total
    {/if}
  </svelte:fragment>
</DataTable>

<LinkDownload
  data={toCsv(headers, rows)}
  filename="load-balancers.csv"
  type="text/csv;charset=utf-8"
>
  Download CSV
</LinkDownload>
data-table-footer data-table-csv

Leaner prebuilt theme CSS

The compiled theme sheets are smaller after vendoring Carbon SCSS in-repo, pruning unused partials, and dropping selectors this library never emits. The npm package is also lighter because it no longer ships SCSS sources. See #3636.

Sheet Before After Δ raw Δ gzip
white.css 782.9 KB (76.1 KB gzip) 721.3 KB (69.2 KB gzip) -61.6 KB (-7.9%) -6.9 KB (-9.0%)
all.css 976.6 KB (91.2 KB gzip) 909.3 KB (83.7 KB gzip) -67.3 KB (-6.9%) -7.5 KB (-8.2%)

Prefer the prebuilt themes:

import "carbon-components-svelte/css/white.css";

Menu: selectable items, shortcuts, scroll, and icon-only triggers

MenuItemGroup and MenuItemRadioGroup hold checkbox and radio state. shortcutText shows a keyboard hint. maxHeight scrolls long menus. MenuButton adds an iconOnly trigger for row actions with submenus.

See selectable, shortcuts, scrollable, and icon-only.

<script>
  import { MenuButton, MenuItem, MenuItemGroup } from "carbon-components-svelte";

  let selectedIds = ["name"];
</script>

<MenuButton labelText="View">
  <MenuItemGroup labelText="Columns" bind:selectedIds>
    <MenuItem id="name" labelText="Name" />
    <MenuItem id="size" labelText="Size" />
    <MenuItem id="modified" labelText="Last modified" />
  </MenuItemGroup>
</MenuButton>

<MenuButton iconOnly labelText="Row actions">
  <MenuItem on:click={() => console.log("Rename")}>Rename</MenuItem>
  <MenuItem labelText="Export as">
    <MenuItem on:click={() => console.log("PDF")}>PDF</MenuItem>
    <MenuItem on:click={() => console.log("CSV")}>CSV</MenuItem>
  </MenuItem>
</MenuButton>
menu-button

Slider and RangeSlider: marks and formatValue

Tick marks along the track (marks as an array of stops, or true for every step). formatValue formats range labels and aria-valuetext (currency, percent) while bound values stay numeric.

See formatted values and marks.

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

<Slider
  labelText="Intensity"
  hideTextInput
  min={0}
  max={3}
  step={1}
  value={1}
  marks={[
    { value: 0, label: "Off" },
    { value: 1, label: "Low" },
    { value: 2, label: "Med" },
    { value: 3, label: "High" },
  ]}
/>

<Slider labelText="Opacity" value={75} formatValue={(v) => `${v}%`} />
range-slider-marks

Tabs: selectedId, manual activation, and lazy panels

Bind selectedId so selection survives tabs being added or removed. Set activation="manual" so arrow keys only move focus. lazy and unmountOnHide on TabContent defer or tear down heavy panels.

See selected by id, manual activation, and lazy content.

<script>
  import { Tab, TabContent, Tabs } from "carbon-components-svelte";

  let selectedId = "dashboard";
</script>

<Tabs bind:selectedId activation="manual">
  <Tab id="dashboard" label="Dashboard" />
  <Tab id="monitoring" label="Monitoring" />
  <svelte:fragment slot="content">
    <TabContent lazy>Dashboard content</TabContent>
    <TabContent lazy unmountOnHide>Monitoring content</TabContent>
  </svelte:fragment>
</Tabs>

Accordion: flush, single-open, and lazy items

flush removes the gutter for full-bleed layouts. type="single" closes other items when one opens. Set lazy on AccordionItem to defer mounting panel content until first expand.

See flush, single-open, and lazy loading.

<script>
  import { Accordion, AccordionItem } from "carbon-components-svelte";
</script>

<Accordion type="single" flush>
  <AccordionItem lazy open title="Overview">
    <p>Panel content mounts on first expand.</p>
  </AccordionItem>
  <AccordionItem lazy title="Details">
    <p>Only one item stays open at a time.</p>
  </AccordionItem>
</Accordion>
accordion-flush

Dropdown clearable and MultiSelect selection caps

Set clearable on Dropdown to reset the selection. MultiSelect adds maxSelectedItems, Shift+click range selection, and live announcements of filter result counts in the filterable variant. ComboBox, Dropdown, and MultiSelect emit scrollend near the menu bottom for load-more patterns.

See clearable dropdown and maximum selection.

<script>
  import { Dropdown, MultiSelect } from "carbon-components-svelte";

  const items = [
    { id: "email", text: "Email" },
    { id: "slack", text: "Slack" },
    { id: "sms", text: "SMS" },
    { id: "push", text: "Push" },
  ];
</script>

<Dropdown clearable labelText="Contact" {items} />

<MultiSelect maxSelectedItems={3} labelText="Preferences" label="Select preferences..." {items} />
dropdown-clearable multi-select-max

Modal: hide close, loading submit, and richer secondary buttons

hideCloseButton removes the header close control for forced-choice dialogs. primaryButtonLoading shows an inline spinner during async submit. secondaryButtons now accept kind and disabled per button. Same hideCloseButton lands on ComposedModal.

See hide close button and primary button loading.

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

  let open = true;
  let loading = false;
</script>

<Modal
  bind:open
  modalHeading="Accept terms"
  primaryButtonText="Accept"
  primaryButtonLoading={loading}
  hideCloseButton
  preventCloseOnClickOutside
  secondaryButtons={[{ text: "Remind me later", kind: "ghost" }]}
>
  <p>You must accept to continue.</p>
</Modal>
modal-hide

DatePicker: year type

Pick a year without day- or month-level granularity. Set datePickerType="year" for fiscal years, reporting periods, and other year-scoped forms. The calendar shows a decade grid; pair it with dateFormat="Y".

See year picker.

<script>
  import { DatePicker, DatePickerInput } from "carbon-components-svelte";
</script>

<DatePicker datePickerType="year" dateFormat="Y">
  <DatePickerInput labelText="Fiscal year" placeholder="yyyy" />
</DatePicker>
year-calendar

Pagination simple mode

Compact previous/next with page status text. Useful in toolbars and cards.

See simple pagination.

<script>
  import { Pagination, Toolbar, ToolbarContent } from "carbon-components-svelte";
</script>

<Toolbar size="sm">
  <ToolbarContent>
    <Pagination simple size="sm" totalItems={102} pageText={(page) => `${page.toLocaleString()}`} />
  </ToolbarContent>
</Toolbar>
pagination-simple

Tag: links and maxWidth

Set href to render a tag as an anchor. Set maxWidth to ellipsis long labels; a tooltip with the full text appears only when truncated.

See link tags and max width.

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

<Tag href="/components/Tag" type="blue">Svelte</Tag>

<Tag filter maxWidth="8rem" on:close>
  Very long filterable label that truncates
</Tag>
tag-link tag-max-width

Checkbox invalid and warn states

Validation and warning text on Checkbox and CheckboxGroup. Group state takes precedence over individual checkboxes.

See checkbox states.

<script>
  import { Checkbox, CheckboxGroup } from "carbon-components-svelte";
</script>

<Checkbox
  labelText="I agree to the terms and conditions"
  invalid
  invalidText="You must agree to the terms and conditions to continue"
/>

<CheckboxGroup
  warn
  warnText="Push notifications may be delayed"
  legendText="Notification preferences"
  name="prefs"
  selected={["email"]}
>
  <Checkbox labelText="Email" value="email" />
  <Checkbox labelText="Push" value="push" />
</CheckboxGroup>
checkbox-invalid

UserAvatar: interactive, href, and image fallback

Set interactive to render a focusable button, or href for a profile link. Failed images fall back to initials or the default icon. Pass imageAttributes for loading, srcset, and similar img attributes.

See interactive and link.

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

<UserAvatar interactive name="Richard Hendricks" backgroundColor="purple" />

<UserAvatar href="/profile" name="Richard Hendricks" backgroundColor="blue" />

<UserAvatar
  name="Monica Hall"
  image="https://example.com/monica.jpg"
  imageAttributes={{ loading: "lazy" }}
/>
user-avatar-interactive

Form: actions for SvelteKit enhance

Svelte's use: directive cannot target components. Pass actions={[enhance]} (or [action, parameter] tuples) to apply SvelteKit enhance to the underlying <form>. FormGroup also supports disabled.

See SvelteKit enhance.

<script>
  import { enhance } from "$app/forms";
  import { Button, Form, TextInput } from "carbon-components-svelte";
</script>

<Form method="POST" action="?/save" actions={[enhance]}>
  <TextInput name="name" labelText="Name" />
  <Button type="submit">Save</Button>
</Form>

More in this release

  • TextInput: maxCount character counter (grapheme-aware, shared with TextArea)
  • CodeSnippet: configurable collapsed row counts; copy falls back to execCommand and surfaces errors (CopyButton / CopyInput too)
  • FileUploader: per-file status; drop container size and duplicate rejection parity
  • PinCodeInput: custom pattern, form name, multi-character autofill
  • NotificationQueue: top-left / top-center / bottom-* placements; pauseOnHover on toast and inline notifications
  • ContentSwitcher / ProgressIndicator / Tabs: stable selectedId
  • ContainedListItem: href for link rows
  • Dialog: close trigger detail and focus restore
  • OverflowMenu: maxHeight for scrollable menus

Breaking changes

CSS: prebuilt themes only (individual .scss removed from the package)

The npm package no longer ships css/**/*.scss (including theme entries like white.scss) or the vendored Carbon SCSS under css/vendor/. Import the prebuilt themes instead:

import "carbon-components-svelte/css/white.css";

Those published SCSS files were never a real consumer API: they imported carbon-components, which was only a devDependency of this repo, and they also pulled in library-owned patches that only compile as a unit inside our bun build:css pipeline. The supported path has always been the prebuilt CSS.

The upside is the leaner sheets in the table above and a lighter package, without needing carbon-preprocess-svelte. Details in #3636. SCSS sources stay in the git repo for building themes.

DataTable: bind:selectable no longer flips

bind:selectable no longer becomes true when radio or batchSelection is set. Read radio / batchSelection directly if you need that signal.

MultiSelect: trigger named by field label

The non-filterable trigger is named by its field label. Review any custom accessible-name workarounds.

Tag: no forwarded on:click on non-interactive tags

Non-interactive tags no longer forward on:click. Use filter, interactive, or href when the tag should be clickable.

ContextMenuOption: icon and indent are presentational

A selectable or radio-group option no longer overwrites icon / indented on the exported props. The checkmark and indentation are computed internally.


What's Changed

Breaking Changes

Features

Bug Fixes

  • fix(accordion-item): link header button to its content region (#3572) by @metonym in a0910af
  • fix(accordion): keep nested accordion items independently collapsible by @metonym in 2f3c98e
  • fix(code-snippet): set aria-expanded on the show-more button (#3573) by @metonym in dc49776
  • fix(code-snippet): update previous-state guard before dispatching by @metonym in acafcc7
  • fix(combo-box): support Home/End keys in the open listbox by @metonym in 9a0e78e
  • fix(combobox): stop option-click focus bounce, drop aria-owns by @metonym in 0e4495c
  • fix(composed-modal): name the scrolling content region (#3577) by @metonym in 8ad7258
  • fix(content-switcher): prevent arrow keys from scrolling the page by @metonym in 9f686de
  • fix(context-menu-option)!: stop clobbering the icon and indented props (#3582) by @metonym in 7310270
  • fix(context-menu): keep menu open on selection via preventDefault by @metonym in f1b1fd1
  • fix(context-menu): restore focus to parent option when submenu closes (#3549) by @metonym in dc47b70
  • fix(data-table): fix tooltip link color in tables by @metonym in 53e946d
  • fix(data-table): label the selectable checkbox column header by @metonym in eee2a74
  • fix(data-table): label the table with its title and description (#3574) by @metonym in cbb969d
  • fix(data-table): set aria-expanded on row expansion buttons (#3560) by @metonym in 434f11c
  • fix(data-table)!: stop clobbering the bound selectable prop (#3580) by @metonym in b1f00c4
  • fix(data-table): unsubscribe toolbar search before resubscribing (#3567) by @metonym in 181963d
  • fix(date-picker): mark today in month view, matching day/year cells by @metonym in 370f121
  • fix(date-picker): use layout viewport width for portalMenu right-align (#3644) by @b-r-i-a-n-w-e-s-t in bc46937
  • fix(date-picker): use theme-aware color for current year, add aria-current by @metonym in c1cd181
  • fix(dropdown,combobox): keep disabled options in keyboard navigation (#3547) by @wickning1 in 569ae1c
  • fix(dropdown,multi-select): support Home and End keys in the open listbox by @metonym in f27c7e9
  • fix(dropdown): add keyboard clearing, announce cleared selection (#3643) by @metonym in c6e0fa7
  • fix(dropdown): guard highlighted item lookup when items change while open (#3615) by @metonym in eb540f8
  • fix(dropdown): stop option-click focus bounce, add virtual aria attrs by @metonym in b8cf75c
  • fix(hamburger-menu): set aria-expanded on the menu toggle (#3579) by @metonym in e31a1d3
  • fix(header-action): add aria-expanded and close on Escape (#3552) by @metonym in 0c7c956
  • fix(menu-item): prevent ArrowLeft from scrolling the page when closing a submenu by @metonym in 1c2305a
  • fix(menu): keep menu open on selection via preventDefault by @metonym in 0a716f8
  • fix(multi-select): add keyboard clearing to the non-filterable variant, announce cleared selection (#3642) by @wickning1 in 398bb39
  • fix(multi-select): keep disabled options in keyboard navigation (#3546) by @wickning1 in 4a4dcbe
  • fix(multi-select): make Space toggle the highlighted option, add Home/End (#3590) by @wickning1 in ff608c9
  • fix(multi-select)!: name the non-filterable trigger by its field label (#3548) by @wickning1 in b8d626d
  • fix(multi-select): prevent page scroll on arrow keys in filterable read-only mode (#3641) by @wickning1 in 473ef05
  • fix(multi-select): resolve dangling aria-describedby for invalid and warn text (#3640) by @wickning1 in 139abab
  • fix(multi-select): set aria-setsize/aria-posinset on virtualized options by @wickning1 in 56a3bfe
  • fix(multi-select): stop the option-click focus bounce, drop aria-owns by @wickning1 in 9b7b027
  • fix(pagination-nav): emit 1-based page index from single overflow item (#3620) by @metonym in c50b9fe
  • fix(profile-menu): align aria-haspopup with the panel's actual semantics (#3578) by @metonym in e4958e3
  • fix(progress-indicator): expose step state to assistive tech (#3569) by @metonym in 1befca2
  • fix(range-slider): prevent arrow/Home/End keys from scrolling the page by @metonym in b4679ab
  • fix(search): update previous-state guard before dispatching by @metonym in d1adf09
  • fix(side-nav): close the overlay side nav on Escape (#3575) by @metonym in b7d1804
  • fix(skeleton): hide skeleton placeholders from assistive tech (#3576) by @metonym in d44e631
  • fix(slider): guard thumb position when min equals max (#3616) by @metonym in dceae34
  • fix(slider): prevent arrow/Home/End keys from scrolling the page by @metonym in 24ee8f9
  • fix(slider): support Home and End keys (#3553) by @metonym in 6ee3917
  • fix(structured-list): scope focus style to selected row by @metonym in b2e036b
  • fix(structured-list): silence unused export warning on deprecated tabindex (#3451) by @metonym in d793ea5
  • fix(tabs): link tabs to their panels with aria-controls (#3571) by @metonym in c33bdd7
  • fix(tabs): prevent arrow keys from scrolling the page by @metonym in aec04ca
  • fix(tag)!: remove forwarded on:click event from non-interactive tags (#3540) by @anishrajpandey in 64a2812
  • fix(text-area): associate helper text and character count with the textarea (#3570) by @metonym in 913cd5e
  • fix(text-area): count graphemes for maxCount, not UTF-16 units by @metonym in 7196ba8
  • fix(text-input): count graphemes for maxCount, not UTF-16 units by @metonym in f00961a
  • fix(toggletip): update previous-state guard before dispatching by @metonym in 83503f0
  • fix(toolbar-batch-actions): announce selection count and manage focus on dismiss (#3563) by @metonym in 051a92c
  • fix(tooltip-definition): update previous-state guard before dispatching by @metonym in 5cac056
  • fix(tooltip-icon): update previous-state guard before dispatching by @metonym in 770833e
  • fix(tooltip): update previous-state guard before dispatching by @metonym in c7bb0e6
  • fix(tree-view): dedupe selectedIds on Ctrl+A / range-select (#3612) by @metonym in 672cc0d
  • fix(utils): add graphemeCount for user-perceived character counts by @metonym in 738743a
  • fix(utils): guard getVisibleRange against non-positive itemHeight (#3618) by @metonym in 7545eb9
  • fix(utils): handle empty palette in getAvatarBackgroundColor (#3619) by @metonym in 461c60f

Performance

Don't miss a new carbon-components-svelte release

NewReleases is sending notifications on new releases.