Changelog
What changed in each version, from newest to oldest. Check the "Before upgrading" section of
each version first: that's where the changes your project needs are. The same notes are in
CHANGELOG.en.md.
0.37.2
Fixed
- A
<select class="tuc-input" data-tuc-select>made the page scroll horizontally. The.tuc-inputrule outweighed the one that hides the native element and gave it backwidth: 100%; absolutely positioned inside an unpositioned parent, the invisible native select took the page's width and sat shifted to the right. The hidden native select now stays 1px in every case — disabled andmultipletoo — and submission,required,resetand<label>work as before.
- A
0.37.1
Fixed
- The tooltip showed up on its own after a modal closed. Clicking a button with
data-tuc-tipopened the<dialog>, and on close the browser returned focus to the button — and that focus opened the tooltip, with nobody pointing at it or tabbing to it. On a button that only appears on hover, the bubble floated over nothing. Focus now opens the tooltip only when it comes from the keyboard (:focus-visible, and not right after a click);Tabto the element still shows it, and hover,Escapeand touch are unchanged.
- The tooltip showed up on its own after a modal closed. Clicking a button with
0.37.0
New
- Button group, class only:
.tuc-btn-group. On its own it joins actions that belong together —[Edit][Duplicate][Archive]becomes one block instead of three loose buttons on the line. Withis-segmentedit dresses the<input>as a button: the segmented tab's box, with the chosen one in the theme's accent colour, and the value still belongs to the native control —name,value,required, the POST and the arrow keys are the browser's. The<input>goes inside the<label class="tuc-btn">, withclass="tuc-btn__input", and has zero opacity rather than being hidden, so it stays focusable and announced. Withtype="checkbox"several can be on at once, andis-blocktakes the whole line. It does not replace the segmented tab: that one changes what is on the screen, this one is a field and goes in the POST.
- Button group, class only:
0.36.0
New
- The editor gained variables:
variables: [{ name, label, example }]adds a toolbar button and opens a list when you type{, filtered by what follows the brace, writing{{nome}}into the text — plain text, the way the server template already expects it.editor.unknownVariables()points out what is written in the text but missing from the list, the usual typo. Inside a code In the text a variable shows with a light background, and one missing from the list comes out in the error tone — the browser painting over the range, with no markup in the content, so the saved value does not change. Inside a code block the list does not open and nothing is flagged — that is where code goes, including a template's own{{ nome }}as an example. Withoutvariables, nothing changes in the editor.
Changed
- A dropdown opened by click no longer highlights the first item: with the pointer somewhere else, a highlighted item looked like a choice already made. The first arrow key is what highlights. Opened from the keyboard (
Enter,Spaceor an arrow on the trigger), the first item still starts highlighted. This also covers the right-click menu and the variables list, which are the same menu.
- The editor gained variables:
0.35.0
New
- Right-click menu (
ContextMenu,data-tuc-contextmenu): the same dropdown menu, opened at the click point.matchsays which part of the area is the target,itemsalso takes a function to build the clicked row's actions, and the browser's menu stays onShift+ right-click. The menu key andShift+F10open from the focused target.
Changed
- The dropdown's group label is no longer uppercase. "CONTRACT" shouted louder than the menu items themselves.
- Right-click menu (
0.34.0
Before upgrading
- The value of an empty editor changed from
<p><br></p>to'', ingetValue()and in the<textarea>that goes in the POST. Code that detected emptiness by comparing to<p><br></p>, in JavaScript or on the server, now gets an empty string — and arequiredfield now blocks the submit, as it should. - With the script loaded with
defer, auto-init now waits forDOMContentLoadedinstead of running the moment the script executes. That is what leaves room to callTucano.setTexts()before the components mount. A script of yours, also deferred, that readelement._tucanoright when it ran now findsundefined: read it inside aDOMContentLoadedlistener. - The Brazilian real currency format was renamed from
realtobrl, in English like the other code names:data-tuc-mask="brl",data-tuc-format="brl",format: 'brl'andTucano.FORMATS.brl.realno longer works: the field gets no mask and display text shows raw. Tucano.mask.format(value, 'document'), an undocumented alias of'cpf-cnpj', was removed. Use'cpf-cnpj'.- The table events now share the prefix of the others:
tuc:sortis nowtucano:sort, andtuc:selectistucano:select. The old names no longer fire. - The date picker's
openOnFocusoption was removed. It only existed to keep the old behavior of opening the calendar when tabbing in; opening is still↓,Spaceon an empty field, or a click. - The select's server search only reads the documented response formats:
[{value, label}],["a", "b"], DRF's{results: [...]}and Select2's{id, text}, withnextto tell whether there is another page.{items},{data},pk,nameandhas_moreare no longer read: answer in one of the formats above or useloadOptions. - Portuguese names left in code:
Popoverpasses the reasons'focus'and'detached'toonDismiss(they were'foco'and'solto'), and the color picker area's custom property is--hue(it was--matiz). - State classes that no CSS rule read are gone — the select's
is-multipleandis-empty, the upload'sis-empty, the date picker'sis-rangeandis-timed— and so is theidproperty of aTableinstance, which nothing used. If your project relied on them, use.tuc-select-native[multiple] + .tuc-select,.tuc-select:not(.has-value),instance.isRange,instance.opts.timeand the<table>'s ownid. - The CSS got almost 1 KB smaller (gzip) without the fallbacks Tailwind injected for old browsers. Below Chrome 111, Safari 16.2 and Firefox 113 — Tailwind 4's own baseline — soft backgrounds, focus rings and the off switch track, which use
color-mix, no longer show. And component font weights are fixed at 500 and 600 instead of reading your project's Tailwind theme. - Date picker with the Apply button (the default with
time, orautoApply: false): picking a day, time or preset no longer firestucano:change,changeoronChange. The event fires once, on Apply, and closing withEscapeor a click outside discards the choice. Before, every click already emitted, Apply emitted again and closing outside kept the change. WithautoApply: truenothing changes. Code that saved on every event now only gets the confirmed value. - Dates outside
minandmaxare no longer pulled to the limit. Typed, they are refused and the previous value stays; insetValue()and in the initialvalue, the field is left empty, as already happened withdisabledDates. Before,2027-01-15withmaxat2026-12-31silently became 12/31/2026. A typed range without a valid end is also refused whole, instead of keeping just the start. Tucano.dates.parseISO()only reads ISO (yyyy-mm-dd, with optional time) andDate. Text in any other format fell back tonew Date(text), which reads07/09/2026as July 9, and now returnsnull. For what people type, useTucano.dates.parseUserInput().- In the color picker, the native
changefires only once, when a drag on the area or the tracks ends, as with<input type="range">.tucano:changeandonChangestill fire on every move. Before, the native event fired on every pixel, and anhx-trigger="change"sent one request per mouse move; code that usedchangefor a live preview should listen totucano:changeinstead. - The color picker's hue stops at 360 with the keyboard instead of wrapping to 0:
→at the end of the track no longer does anything.HomeandEndgo to the ends. - Direct upload only sends the
X-CSRFTokenread from the cookie to the page's own origin, as in Django's recipe. It used to go along with the file to anyurl, including another domain. If you upload to another origin and need the token, passheaders: { 'X-CSRFToken': ... }. - In direct upload of an input with a
name, a 2xx response without the id (responseId) leaves the file in error, with "O servidor não devolveu o id". It used to show as ready, with the check mark, while the form posted nothing. - A color field with no
valuenow starts empty, instead of arriving with a color the component picked on its own.requirednow blocks the submit while nobody has picked one, and the form no longer posts a color nobody asked for.getValue()returnsnullin that state, andsetValue(null)orsetValue('')clears it. Anyone relying on the built-in color setsvalue="#4f46e5"on the field itself. - In the select,
setValue(value, { silent: true })andclear({ silent: true })now also hold back the native element'schange, not justonChangeandtucano:change. That is what the DOM does when a script writes toselect.value. Anhx-trigger="change"was not silent at all and fired a request on every programmatic change. Call it withoutsilentto notify; picking with the mouse or keyboard still fires.
New
data-tuc-revealalso works on loose text on the page, not only on fields: a CPF on a profile, the card number in a table cell, an API key in a paragraph. The text shows hidden, with the eye next to it, in the same modes (end,email,all) and together withdata-tuc-format. It is visual only: the full value is still in the HTML, so anything that must not reach the browser has to be hidden on the server.Tucano.setTexts()replaces any text the components show or announce: the date picker's "Limpar" and "Aplicar", the range presets, the select's "Buscar..." and "Nenhum resultado", the "Fechar" of modal, drawer and toast, the editor buttons, the mask's "Mostrar"/"Ocultar" and the labels read by screen readers. A project in English or Spanish no longer shows Portuguese. Texts are replaced per group (Tucano.setTexts({ datepicker: { clear: 'Clear' } })), apply to whatever mounts afterwards, and the per-instance option (data-placeholder,emptyText,prevText, the upload'stexts) still wins. Portuguese remains the default, with no language dictionaries in the package, andTucano.getTexts()returns the current texts. The day name that screen readers read in the calendar now comes from the page language.- TypeScript types ship with the package, in
dist/tucano.d.ts, generated from the code on every build and adding nothing to the bundle.import { DatePicker } from 'tucano'and the globalTucanofrom the<script>tag (withcheckJs) now get autocomplete and checking for options, methods, whatgetValue()returns in each mode, thedetailoftucano:*events, the groups and keys ofTucano.setTexts(), and theTucano.mask,Tucano.datesandTucano.colorutilities.
Changed
- The
.tuc-alerticon now sits at the middle of the alert's height instead of being pinned to the first line. With a title and body it drifted upward, while the action buttons beside it were already centered.
Fixed
- The select did not fire
inputon the native<select>, onlychange. The browser's fires both, in that order: anhx-trigger="input"never ran, and in Firefox the validation bubble of an invalid submit did not close when the person picked an option. data-tuc-revealon a field withoutdata-tuc-mask, such as a password or a token, threw an error on every keystroke.- An empty password field with
data-tuc-revealstarted visible, switched totype="text", and showed what was typed. It now always starts hidden. - A field with only the eye got
inputmode="numeric", so phones opened the number keyboard for passwords and tokens. And the password field lost the browser'sautocomplete, which got in the way of password managers. - Some default Portuguese texts were missing accents: "Mês anterior", "Próximo mês", "Próximo" and "Selecionar período" in the date picker, "Limpar seleção" in the select and "Saturação e brilho" in the color picker. If a test in your project compares those texts, update it.
Escapein a select, calendar or color picker opened inside a modal closed the modal too. It now closes only the panel.Escapein the color picker left focus on<body>, and the nextTabstarted over from the top of the page. Focus now returns to the swatch, as in the other fields.- The checkerboard behind translucent colors — on the swatch, the preview and the color picker's transparency track — did not show.
- Select, date picker, color picker, menu and tooltip left the DOM at the exact moment the exit animation would end, and the end could look cut off.
- Typed ranges in the date picker:
25-12-2025 a 31-12-2025was cut at the date's hyphens,aaandaécounted as separators, and the "AM" of a 12-hour time split the text. Separators are nowa,atéand-between spaces, and–or—. - Removing a file in direct upload overwrote the
X-CSRFTokengiven inheaders; the upload itself already respected it. - Reopening a modal or drawer less than 200 ms after closing it made the dialog close again right away: the scheduled close was not cancelled. Reopening now cancels the pending close.
- The date picker read ambiguous dates US-style in the initial
valueand insetValue():07/09/2026became July 9 in a Portuguese field, with time too. Text now goes through the locale's parsing, and aDateis taken as is. - A date typed into the date picker didn't fire
tucano:changeoronChange,Enterwith the panel open neither confirmed nor closed, andEscapedidn't discard the text: the preview wrote the value while typing. - Starting a new range and closing with
Escapeor a click outside erased the range that was already chosen. It now comes back. - Closing and reopening the date picker, select, color picker, menu or tooltip within 200 ms removed the panel from the DOM while the component was still open.
- Keyboard focus in the calendar: the arrow onto a disabled day sent focus to
<body>; opening with↓focused day 1, disabled whenminfalls mid-month, instead of the chosen day or today; and with two months the repeated day of the neighboring month got focus, with two Tab stops in the grid. - Clicking or pressing
Enteron the calendar's arrows, month label, month and year cells, presets and times sent focus to<body>. - Wrong week number in the calendar when the week starts on Sunday, as in pt-BR and en-US: it showed the previous week's.
- Date picker time columns: every button was a Tab stop (194 with seconds) and the arrows did nothing. Each column is now a single stop,
↑,↓,HomeandEndmove within it, andEnterorSpacepick. - The date picker's
destroy()left the field withoutname, so the form stopped posting, plus the attributes, the class anddata-tuc-ready, which keptTucano.initfrom mounting it again; in native mode the wrapper and the overlay stayed. Andnew DatePickertwice on the same field created two instances: the second now replaces the first. form.reset()left the date picker out of sync: the field showed the rawvaluetext and the hidden input kept the old value.- Date picker: in native mode with time,
maxblocked every time on the last day; range presets with time ended at midnight ("Hoje" was 00:00 — 00:00); in a 12-hour locale the panel's time readout showed 24-hour time; anddata-native="auto"wasn't read. - The calendar's month and year views ignored
minandmax. What falls outside is now disabled, and so are the arrows. - The date picker's compact layout was decided only at mount: widening the screen or rotating the tablet left the field without typing and without a mask.
- The calendar grid had no
role="row", and the region that announces the month change was recreated on every render, so screen readers didn't announce it. - Dragging a passage from another page into the editor brought its HTML along — heading, color, style and
<img>, which the browser even downloaded. Dropping now comes in as plain text, like pasting. - The editor's sanitizer accepted
//site.comand/\site.comas local paths, so the saved link pointed to another domain. - Editor link box: a typed
javascript:became a clickable link in the area (the saved value was clean); an address without a scheme, such asexample.com, silently vanished on save and now getshttps://; and changing the address with the cursor inside the link split it in two. Enterand pasting inside an editor code block lost the line breaks on repaint, and the lines merged into one.Tabin an editor table moved only one cell and never left an empty cell. It now walks through all of them and adds a row at the last one.- The editor's
placeholdernever showed. requiredon the editor didn't work: untouched, it blocked the submit without showing where; cleared, it posted<p><br></p>and passed. And the form'sresetdidn't bring the editor back to its original content.- A table inserted in the editor landed inside the cursor's paragraph, left an extra
<p></p>in the value, and the nextCtrl+Zundid the text and kept the table. - Selecting bold text outside the editor lit up the Bold button of every editor on the page.
- A list applied to a paragraph left
<p></p>before and after it in the saved value. - The editor's
destroy()left_tucanoand the class on the textarea, and the scheduled repaint still ran. - In Safari,
Enterinside an editor code block started a new block instead of breaking the line, and pasting or dropping multi-line text there produced one block per line. - In Safari, an editor toolbar button triggered from the keyboard (
Tabto it, thenSpaceorEnter) applied the command to an empty caret at the start of the text instead of the selected text. - In Firefox,
Ctrl+Zright after inserting a table in the editor did not remove it. - In Firefox, changing a link's address with the caret inside it left an empty
<a>in front of the link in the saved value. - The color picker panel could not be reached with the keyboard: with focus on the swatch, the next
Tableft the field and the panel closed. Opened with↓, or withEnterandSpaceon the swatch, focus now moves into the color area, andTabmoves within the panel. The tracks gainedHomeandEnd. Tucano.color.parseColor()and the color picker wrote garbage from valid CSS colors: a percentage alpha, as inrgb(255 0 0 / 50%), came out as#ff0000NaN, andhsl(120, 200%, 50%)came out as#-7f17f-7f.rgb()andhsl()now read%, the alpha slash,degandturn, each part is clamped to its range, and anything that is not a number rejects the color.Tucano.color.formatColor()returnedhsl(360, …)for a hue near the end, which read back as 0, and#rrggbbfffor opacity of 0.998 and up.- Typing a color into the color picker field fired the native
changetwice — with HTMX, two requests — and a key at the edge of the area emitted the same value again. form.reset()left the color picker's swatch and instance with the old color.- A disabled or read-only color picker, or one inside
<fieldset disabled>, opened the panel and let the color be changed. - With
alpha: false, an initial value with opacity, such as#ff000080, stayed in the color picker field with the opacity track hidden. - The color picker's
destroy()leftdata-tuc-ready, soTucano.initdid not mount the field again. Andnew ColorPickertwice on the same field nested one control inside the other, with two swatches: the second now replaces the first. - Color picker palette:
data-swatcheswithrgb(255, 0, 0)was split at the commas into three broken swatches; the selection mark ignored opacity, so#00ff0080and#00ff00lit up together; and the hover growth did not animate. - Color picker: invalid text in the panel field stayed there after committing, misreporting the value; right-clicking the area changed the color along with opening the context menu; and gray or black through
setValue()or typing jumped the area to red instead of keeping the hue. - Single-file upload: choosing a rejected file wiped the one already chosen, and in direct mode it also called its
DELETEon the server. - Form upload:
resetemptied the input, but the list kept showing files the submit no longer carried. - Upload
destroy()during a transfer let the request go on and still emittedtucano:change; in direct mode the input came back without itsname. - Upload: the hidden native input was a
Tabstop with no visible focus, and removing a file — or another one finishing — dropped focus onto<body>. - Upload inside a
<label>: clicking the zone opened the file dialog twice in Firefox and Safari. - A disabled upload, on the input or in a
fieldset, accepted files dropped on the zone, and in direct mode uploaded them. - Direct upload: a lowercase
'x-csrftoken'inheaderswas joined with the cookie token; the id went unencoded into theDELETEURL, so../escapeddeleteUrl; hidden inputs ignored the input'sformattribute;clear()during a transfer emitted twice; and dropping many files at once redrew the list for each one. data-max-size="2M"and other spellings without the "b" silently meant "no limit". Now2M,300kand1 MiBwork, and an unreadable value warns in the console.- Select search: typing with accents (
pará,são) found nothing — only the option was folded, not the typed term. - Select with server search: going back to a term still in flight froze the list on "Buscando..."; the response for an abandoned term showed up during the debounce and on reopening;
minChars: 0did not search on open; and a term served from the cache stopped paginating. - Remote select pagination: a server that ignores
pagecaused endless requests; loading the next page reset the scroll and the highlight to the top; and an error on it wiped the page already on screen. - Select inside a
<label>: the click that opened the panel closed it right away. Focus that reaches the native<select>— through<label for>or the required-field prompt — goes to the search, and the field reads its accessible name from the<label>,aria-labeloraria-labelledby. - A disabled select still allowed typing and clearing with the X, and did not look disabled. An option inside
<optgroup disabled>could be picked, andBackspacein multiple mode removed tags of disabled options. - Select keyboard:
Enterin multiple mode after filtering checked a different option;↑with no active option did not go to the last one;HomeandEndstopped on disabled options; a pointer resting over the list stole the arrow highlight (in Safari, on every scroll); andaria-activedescendantkept pointing to an option that was not on screen. - Select: clicking a group heading, the clear X or a tag's X took focus away from the search; picking the already chosen option again fired
change;setValue()with two values on a single select showed one and posted the other (the first one wins); a blank<option value=""></option>wiped the placeholder;destroy()leftdata-tuc-ready; andform.reset()in remote mode left the field empty. - The select's
refresh()did not turn search on when the options arrived after mounting, and the menu of a long label overflowed a phone's width, scrolling the page sideways.
- The value of an empty editor changed from
0.33.1
Fixed
- In a single select,
BackspaceandDeletewith the search empty did nothing: only multiple mode responded, removing the last tag. Someone who tabbed to a filled select could not empty it without reaching for the X with the mouse. Both keys now clear the value, like the X. Withclearable: falsethere is no X, and the keyboard does not clear either. - Clearing a single select with no
<option value="">— by the X or by the keyboard — showed an empty field, but the<select>fell back to its first option on its own and the form posted the old value. The native element now ends up with nothing selected: the field is not posted, andrequiredblocks the submit. - Typing into a searchable select with the list closed lost the first letter: it opened the list, and opening cleared the search. "sa" became "a". The search now keeps everything typed, remote selects included.
- The form's
reset()put the<select>back to its initial value, but the component kept showing the old one, because reset does not firechange. The display now follows the reset.
- In a single select,
0.33.0
Before upgrading
- The default accent color is now neutral:
#0a0a0ain light mode and#fafafain dark mode, with the text on top inverted. The color belongs to your project, and the package doesn't impose a brand. If you don't set--tuc-accent, the primary button, checked box, active tab and selected day will change from orange to black (or near-white, in dark mode). To keep the orange, set in:root, .dark--tuc-accent: #FF7501,--tuc-accent-hover: #FF8A2A,--tuc-accent-fg: #ffffff,--tuc-thumb: #ffffffand--tuc-accent-text: #B84300— the last one#FF7501in.dark. The full recipe is on the Theme page. - The reasons the modal and the drawer pass to
onCloseare now in English, like the rest of the API:'button'instead of'botao'and'backdrop'instead of'fundo'. If your code compares the reason, update both. - In the mask,
data-tuc-reveal,data-reveal-modeandrevealModeare nowendorall(they werefimandtudo), and thecnpj-numericoformat is nowcnpj-numeric. The old names no longer work: update your templates.
New
- Fields with
data-validateturn green when they pass. On a mask, as soon as the value is complete and correct, while typing (data-tuc-valid); red still shows only when leaving the field. On a native.tuc-inputwithdata-validate, the green comes from:user-valid. Without the attribute, nothing changes.
Fixed
- A drawer with content taller than the screen — a long menu, a filter form — overflowed the screen and did not scroll. The body now scrolls and the panel stays the height of the screen, on all four edges; the modal got the same fix.
.tuc-menuin a fixed-height column, such as an app's sidebar, overflowed the column and the whole page scrolled instead. The menu now scrolls on its own there; outside such a column, nothing changes.- With a modal or drawer open, the mouse wheel scrolled the page behind it — over the dimmed backdrop and after the dialog content reached its end. The page now stays still while a dialog is open, and reaching the end of the body no longer passes the scroll on.
- The close X on modals and drawers sat about 2px inside the line where the content and the footer buttons end. The X stroke now ends on that same line.
- Opening a modal or drawer on a page whose scrollbar takes up space (Windows, or macOS with a mouse) made the background content jump sideways: the scroll lock hid the scrollbar and the page gained its width. The scrollbar's space is now reserved while the dialog is open.
- A table with many columns in the editor and in
.tuc-prosewas locked to the available width and squeezed the text to one word per line. Each column now has a minimum width and a wide table scrolls horizontally, on its own, without moving the rest of the text. The saved HTML doesn't change.
- The default accent color is now neutral:
0.32.1
Fixed
- The date picker field declared
aria-expandedwithout a role that accepts it, and screen readers ignored the attribute. It is nowrole="combobox", the ARIA role for a field that opens a panel. - Date picker and select kept
aria-controlspointing at the panel even when closed, when it is not in the DOM — an invalid value for screen readers and for Lighthouse. The attribute now exists only while the panel is open.
- The date picker field declared
0.32.0
Before upgrading
- The default accent color is now the toucan orange,
#FF7501, in both themes, with white text on top (--tuc-accent-fg). The contrast of white on this orange is 2.7; if you need 4.5 on the primary button, set--tuc-accent-fg: #0a0a0ain your own project. Where the accent is the text color itself — link, active menu item, tag — the new--tuc-accent-textapplies, darker in light mode to stay readable. If you already set--tuc-accentin your project, check these two as well. - A file rejected by the upload is a
.tuc-alert is-danger, with the class.tuc-upload__rejected. The.tuc-upload__item.is-rejectedrule no longer exists. - The color picker hex field is a
.tuc-input, and the eyedropper a.tuc-btn is-outline is-sm. - The
tuc-upload__actionandtuc-pagination__icoclasses were removed. - The active
.tuc-menuitem no longer has the stroke on its left border. - Info badge, alert and toast use the new
--tuc-info(blue), and no longer the accent color. If you overrode--tuc-accentto change that shade, override--tuc-infoinstead.
New
- Checkbox, radio and switch:
.tuc-radio,.tuc-switchand the.tuc-choicelabel, which aligns the control with the first line of text, with.tuc-choicesfor groups. - Forms:
.tuc-label,.tuc-hintand.tuc-error, and the invalid state viaaria-invalid="true"on every field — Django 5 already writes the attribute..tuc-inputalso works on the native<select>. - Tabs (
data-tuc-tabs), with ARIA APG keyboard support, a manual mode for panels loaded via HTMX and a segmented variant. - Inline page alert (
.tuc-alert), in four tones. - Loading:
.tuc-spinnerand.tuc-skeleton. A button witharia-busydoes not fade. - Timeline (
.tuc-timeline), class only: tones, filled or hollow dot and an optional icon in place of the dot. - The package exports
icon,ICON_CHECK,ICON_COPYandICON_X. - Documentation with one page per component, generated at build time.
Changed
- Components use the library's own pieces internally: the calendar label and shortcuts are
.tuc-btn, the toast and select loading indicator is the.tuc-spinner, the menu counter is.tuc-badge. - The modal and drawer glow follows the accent color.
Fixed
- The mask currency field started without a placeholder and looked like a plain field. It now shows zero already formatted, such as
R$ 0,00. - The calendar's month navigation arrows were invisible and not clickable.
- A button made with
<a>came out underlined. - Upload, the dropdown danger item and the mask invalid field used hardcoded red and green, which did not lighten in dark mode.
- The tabs panel focus ring rose above the list.
- The server search error looked the same as "no results".
- In the date picker, opening with
↓orEspaçoleft focus on the field: the arrows did not reach the days andTabclosed the panel. Focus now moves to the day. - The mask cleared the field's
aria-invalidon focus, and the error Django sent disappeared on the first click. Now only the mask's own validation touches it. setValue()on the sensitive field did not update the value submitted with the form.- The editor toolbar only responded to the mouse: with focus on a button,
EnterandEspaçodid nothing. They now work, and the command applies to the text that was selected. - The editor's delete row, column and table buttons did not turn red.
- The upload
methodoption was ignored, and the request was always sent as POST. - A toast coming from Django messages got the wrong type when the message had
extra_tags: it read only the first word. Tooltip.setText()removed the arrow along with the text.- An empty
data-tuc-tipstopped the following tooltips from mounting. - A dropdown created in JS with
panelleft its items withoutrole="menuitem". - Select, date picker and color picker inside a modal or drawer opened the panel behind the dialog. The panel is now created inside the open
<dialog>. - A modal without a title had no name for screen readers; the text now names it.
- The dialog left the DOM 10 ms before the exit animation finished.
- In pagination, the ends had no name on mobile, and
setPage()lost focus for keyboard users. - The range date picker misread its own ISO value (
2026-03-01,2026-03-15), which is what Django returns when the form comes back with errors. - Changing
--tuc-accentor a tone on a container did not change the soft background or the focus ring, which stayed in the root color. - The code highlighter painted the rest of the line as a comment after
https://, and every CSS hex color (#4f46e5) as a comment.
- The default accent color is now the toucan orange,
0.31.0
Before upgrading
- The
tuc-menu__secaoclass was removed. Usetuc-menu__section.
Changed
- Test suite in the repository and in CI: pure functions, in-browser behavior, real keyboard, documentation examples checked against the code and cross-checks of names.
Fixed
- The accordion did not expose
node._tucano. - Modal and drawer advertised
actionswith the old keys. toast.promisedocumentedcarregando/sucesso/erroinstead ofloading/success/error.
- The
0.30.2
Fixed
- The 0.30.1 tag did not include the rename of the
tucano:toast-fechadoevent totucano:toast-closed, which npm was already publishing. GitHub, jsDelivr and npm once again have the same content.
New
- Full API reference, generated from the code, inside
llms.txt.
- The 0.30.1 tag did not include the rename of the
0.30.1
Before upgrading
- The API is now entirely in English: method, option, value, CSS class and event names.
Modal.abrir()becameopen(),tom: 'perigo'becametone: 'danger',.tuc-gavetabecame.tuc-drawer. - The table sorts on the server by default; sorting on the page requires
data-sort-mode="client". - Arriving via
Tabno longer opens the field panels. Opening is always explicit.
New
- Table, with sorting and bulk selection, and pagination built for the Paginator.
- Dropdown.
- Status badge, custom-styled checkbox and a copy button on code blocks.
- Fields draw their border and height before the script runs.
Changed
- Tokens on
:rootand a reset with a single selector.
- The API is now entirely in English: method, option, value, CSS class and event names.
0.25.1
- The browser anchors scrolling on its own, with no manual fix.
0.25.0
- Importing
tucanono longer runs anything: the bundler takes only what is used.
- Importing
0.24.2
- Applying a heading in the editor no longer makes the text jump, and links are requested in a modal.
0.23.3
- The scrollbar follows the theme.
0.23.1
- Same content as 0.23.0, published under a different number because npm reserved the previous one.
0.23.0
- Rich text editor with tables, alignment and code blocks. The Markdown field was removed, leaving a single editor.
- The tooltip sits far enough away that the arrow does not touch the trigger.
0.22.1
- All controls measured to have the same height.
0.19.0
- Text editor that shows the result as you type.
0.18.1
- The formatted field preview replaces the field instead of stacking below it.
0.18.0
- Formatted text field, in Markdown.
0.17.1
- The icon no longer overlaps the text in fields with an icon.
0.17.0
- Styling for the textarea, which the library had never had.
0.16.3
- AI files up to date with the library.
0.16.2
- Accordion example with real content.
0.16.1
- Generic names in the example menu.
0.16.0
- Submenu in the sidebar menu, with a rail and highlighting of the open branch.
0.15.1
- The icon follows the button size.
0.15.0
- Sidebar menu, and icons now use the library's button.
0.14.3
- The accordion no longer stutters on first open.
0.14.2
- The accordion collapses all the way to zero, and the background glow spreads further.
0.14.1
- The end of the accordion is no longer cut off, and the drawer glow starts in the right place.
0.14.0
- Accordion built on native
<details>.
- Accordion built on native
0.13.0
- The drawer becomes its own component, on the same base as the modal.
0.12.0
- Drawer (off-canvas).
0.11.1
- A closed
<dialog>no longer covers the whole page. - The advertised sizes now come from the build.
- A closed
0.11.0
- Modal built on native
<dialog>.
- Modal built on native
0.10.2
- Listener leak in the popover.
0.10.1
- Panels positioned with
left/topinstead oftransform.
- Panels positioned with
0.10.0
- Full tooltip: four sides, arrow and customizable color.
0.9.9
- The toast moves to the bottom right corner, and the margin on mobile was fixed.
0.9.8
- Loading toast that turns into the result in the same card.
0.9.7
- The toast's two accessibility regions become a single stack.
0.9.6
- Icon and close button centered in the toast.
0.9.5
- New tooltip animation.
0.9.4
- The toast stack does not close when moving the mouse from one toast to another.
0.9.3
- Toast and tooltip are exempt from the 16px mobile rule.
0.9.2
- Motion reviewed and heights checked.
0.9.1
- A disabled button shows the not-allowed cursor.
0.9.0
- Stacked toasts and button styles.
0.8.0
- Toast and tooltip.
0.7.1
- Fewer requests in server search.
0.7.0
- Server search in Select.
0.6.1
- Hiding modes for the sensitive field, and the password field fixed.
0.6.0
- Masks, document validation and sensitive field.
0.5.2
- Accepted upload types documented.
0.5.1
- Retry icon fixed.
0.5.0
- Upload field.
0.4.2
- Date picker attributes documented on the page.
0.4.1
- Color picker value row aligned.
0.4.0
- Full customization via CSS variables.
- Recursion in the color picker fixed.
0.3.0
- No zoom on mobile when focusing a field, and the custom panel becomes the default.
0.2.1
- Native mode and calendar on mobile fixed.
llms.txtandAGENTS.md, so AI knows how to use the library.
0.2.0
- First release: lightweight form components, with no dependencies.