Auxiliares de preferências
Sete pacotes pequenos por framework, cada um dono de uma tarefa do utilizador de ponta a ponta, mais uma barra que reúne cinco deles. Já conheceu o theme-picker; aqui estão locale-picker, text-size-picker e motion-picker (preferências), share-picker e search-picker (ações), date-time-picker (um valor de formulário) e picker-bar.
O que vai construir
Um painel de definições onde os utilizadores escolhem o idioma e o tamanho do texto — escolhas que se aplicam a todo o documento, persistem entre visitas e lhe custam dois componentes e algumas linhas de CSS. Cerca de 15 minutos.
Antes de começar
Conclua primeiro o tutorial do framework da sua stack. Os exemplos abaixo são em Svelte; os auxiliares de React, Vue, Angular, HTML, Nunjucks e Blazor correspondem contrato a contrato.
A forma que partilham
- Um botão de ícone sem cabeça que abre uma caixa de lista WAI-ARIA APG (ou, no date-time-picker, uma caixa de diálogo de seleção de data) — sem
<select>nativo, para que cada framework obtenha o mesmo comportamento de teclado e os mesmos ganchos de estilo. - Um gancho de classe por pacote (
.locale-picker,.text-size-picker,.share-picker,.date-time-picker), zero CSS distribuído. - Seguro para SSR: as escritas no DOM só acontecem no ciclo de vida mount/effect.
- Limpo para i18n: cada cadeia visível para o utilizador é uma prop.
- Disponível para Svelte (canónico), React, Vue, Angular, elemento personalizado HTML, Nunjucks e Blazor — o mesmo contrato em cada um.
theme-picker, locale-picker e text-size-picker são donos cada um de uma
preferência do utilizador de ponta a ponta (seleção, aplicação ao DOM,
localStorage persistência opcional através da prop storageKey
). share-picker e date-time-picker são diferentes na natureza: share-picker é dono de uma ação — não aplica nada ao documento e não persiste nada — e date-time-picker é dono de um
valor de formulário, porque uma data num formulário é um dado, não uma preferência.
locale-picker — idioma e direção
Deixa o utilizador escolher uma localização e depois escreve lang e
dir na raiz do documento para que a sua biblioteca i18n, o seu CSS e as tecnologias de apoio a sigam. O RTL é detetado automaticamente para árabe, hebraico e outras escritas da direita para a esquerda. Foca-se apenas em sinalizar — a sua biblioteca i18n trata da tradução.
<script>
import LocalePicker from "@lilydesignsystem/svelte-locale-picker";
let locale = $state("en-US");
</script>
<LocalePicker
label="Language"
locales={["en-US", "fr", "ar", "he", "ja"]}
bind:value={locale}
storageKey="my-app-locale"
/>
As opções são rotuladas a partir de uma tabela integrada de nomes de localizações (substituível através de localeLabels), cada opção traz o seu próprio atributo
lang para que os leitores de ecrã pronunciem «Français» em francês, e os códigos com sublinhado como en_US
são convertidos sem perdas para BCP 47 e de volta en-US. Ligue
onChange (ou o valor ligado) ao i18next, ao Paraglide, ao vue-i18n ou ao que usar.
text-size-picker — tamanho controlado pelo leitor
Uma vitória de acessibilidade que demora minutos: o auxiliar define
data-text-size="{slug}" na raiz do documento e o seu CSS mapeia cada valor para um tamanho.
<script>
import TextSizePicker from "@lilydesignsystem/svelte-text-size-picker";
</script>
<TextSizePicker
label="Text size"
sizes={["small", "medium", "large", "x-large"]}
storageKey="my-app-text-size"
/>
:root[data-text-size="small"] { font-size: 87.5%; }
:root[data-text-size="medium"] { font-size: 100%; }
:root[data-text-size="large"] { font-size: 112.5%; }
:root[data-text-size="x-large"] { font-size: 125%; }
Dimensione o seu layout em rem e toda a aplicação escala com a escolha do utilizador. As etiquetas são formadas a partir dos slugs com maiúscula inicial («X Large») ou substituídas com sizeLabels.
Verifique o seu trabalho: escolha «Large» no seletor e o texto da página cresce. Recarregue — continua grande: a escolha ficou guardada em
localStorage. Mude o seletor de idioma para árabe e
dir="rtl" é definido no documento automaticamente.
share-picker — enviar esta página
Um botão de um só glifo que abre a folha de partilha nativa do dispositivo onde existir e, caso contrário, recorre a uma lista de destinos que fornece, mais uma ação de copiar o URL. Não inclui URLs de redes sociais — quais as redes que pertencem ao seu produto é decisão sua, não do sistema de design.
<script>
import SharePicker from "@lilydesignsystem/svelte-share-picker";
const targets = [
{ id: "mastodon", label: "Mastodon",
href: (url, title) => `https://mastodon.social/share?text=${encodeURIComponent(title)}%20${encodeURIComponent(url)}` },
{ id: "email", label: "Email",
href: (url, title) => `mailto:?subject=${encodeURIComponent(title)}&body=${encodeURIComponent(url)}`, newTab: false },
];
</script>
<SharePicker
label="Share this page"
title="An article worth reading"
{targets}
copyLabel="Copy link"
copiedLabel="Link copied"
/>
url tem como predefinição location.hrefpelo que o caso comum não precisa de cablagem. Force um caminho com strategy="list" ou
strategy="native" quando precisar de comportamento consistente entre plataformas para testes ou capturas de ecrã.
date-time-picker — uma data, uma hora ou ambas
Um campo de texto onde pode escrever, mais um botão de ícone que abre uma caixa de diálogo de seleção de data WAI-ARIA APG. Correto para a localização por construção — os nomes dos meses, os nomes dos dias, o primeiro dia da semana e o relógio de 12 ou 24 horas vêm todos de Intl — e o valor é sempre uma cadeia ISO ordenável e sem fuso horário: "2026-03-15" para
mode="date", "09:30" para
mode="time", "2026-03-15T09:30" para
mode="datetime".
<script>
import DateTimePicker from "@lilydesignsystem/svelte-date-time-picker";
let appointment = $state("");
</script>
<DateTimePicker
inputId="appointment"
name="appointment"
label="Choose an appointment date"
locale="en-GB"
bind:value={appointment}
labels={{
previousYear: "Previous year",
previousMonth: "Previous month",
nextMonth: "Next month",
nextYear: "Next year",
confirm: "OK",
cancel: "Cancel",
}}
/>
O valor ISO é idêntico ao que <input type="date">
envia, pelo que pode trocar o controlo nativo por este ou vice-versa sem tocar no seu backend.
motion-picker — respeite o movimento reduzido
O auxiliar define data-motion="{slug}" na raiz do documento. O seu primeiro valor vem da definição
prefers-reduced-motion do sistema operativo do visitante — sempre, sem uma bandeira de adesão, porque o movimento é uma necessidade real de acessibilidade (WCAG 2.3.3). O seu CSS e os seus scripts decidem o que é suprimido.
<script>
import MotionPicker from "@lilydesignsystem/svelte-motion-picker";
</script>
<MotionPicker
label="Motion"
motions={["no-preference", "reduce"]}
storageKey="my-app-motion"
/>
:root[data-motion="reduce"] *,
:root[data-motion="reduce"] *::before,
:root[data-motion="reduce"] *::after {
animation: none !important;
transition: none !important;
scroll-behavior: auto !important;
}
search-picker — uma caixa de pesquisa que não atrapalha
Um botão de ícone que abre um campo de pesquisa. Premir Enter, ou o botão ⏎ junto ao campo, navega com um simples pedido GET para
/?<text> (o texto é aparado e codificado como URI; uma pesquisa vazia não leva a lado nenhum). Os seus três nomes acessíveis são obrigatórios, porque o auxiliar não inclui inglês.
<script>
import SearchPicker from "@lilydesignsystem/svelte-search-picker";
import { goto } from "$app/navigation";
</script>
<SearchPicker
label="Search this site"
inputLabel="Search terms"
submitLabel="Search"
placeholder="Search…"
action="/search"
navigate={(href) => goto(href)}
/>
action altera o caminho (/search?foo), e
navigate mantém a navegação dentro da aplicação; sem ele, o auxiliar chama location.assign.
picker-bar — toda a linha do cabeçalho de uma vez
picker-bar renderiza pesquisa, tema, localização, tamanho do texto e partilha numa só linha, com o conjunto completo de temas de referência e a escala de texto de sete passos já ligados. Cada nome acessível chega num único objeto
labels obrigatório.
<script>
import PickerBar from "@lilydesignsystem/svelte-picker-bar";
</script>
<PickerBar
labels={{
search: "Search", searchInput: "Search terms", searchSubmit: "Search",
theme: "Theme", locale: "Language", textSize: "Text size", share: "Share",
}}
themesUrl="/themes/"
locales={["en", "fr", "es"]}
shareTargets={targets}
/>
Alcance qualquer seletor embrulhado com searchProps,
themeProps, localeProps,
textSizeProps e shareProps.
As dicas já vêm integradas
Cada seletor mostra a sua etiqueta numa dica quando o ponteiro repousa no botão ou o botão tem foco de teclado. A dica permanece enquanto o ponteiro se move para ela, Escape fecha-a onde quer que esteja o foco, e nunca aparece enquanto a janela do seletor está aberta. Leva o mesmo texto que o nome acessível do botão, pelo que não há nada a configurar nem a traduzir duas vezes; os temas de referência estilizam-na.
Um painel de definições num só lugar
Os quatro auxiliares de preferências compõem-se naturalmente:
<fieldset class="fieldset">
<legend>Preferences</legend>
<ThemePicker label="Theme" themesUrl="/themes/" themes={themes} storageKey="pref-theme" />
<LocalePicker label="Language" locales={locales} storageKey="pref-locale" />
<TextSizePicker label="Text size" sizes={sizes} storageKey="pref-text-size" />
<MotionPicker label="Motion" motions={motions} storageKey="pref-motion" />
</fieldset>
Verificado: os excertos de locale-picker, text-size-picker, share-picker, date-time-picker e do painel combinado foram compilados individualmente contra os pacotes 0.1.1 publicados, através de
svelte/server (2026-08-29); os excertos de motion-picker, search-picker e picker-bar foram renderizados contra os componentes dos próprios pacotes em 2026-10-06.
Onde obtê-los
# one directory per package in the monorepo, e.g.
git clone https://github.com/LilyDesignSystem/lily-design-system
cd lily-design-system/lily-design-system-svelte-theme-picker
# or lily-design-system-react-theme-picker, -vue- / -angular- / -html- / -web-components- / -nunjucks- / -blazor-
Cada pacote tem o seu próprio spec, testes mapeados para as cláusulas do spec, exemplos executáveis (incluindo padrões de cookies para SSR) e um pipeline de compilação e publicação. Os pacotes Svelte são os canónicos; em caso de dúvida, os seus contratos prevalecem.
Passos seguintes
- Catálogo de componentes — a referência completa dos 571 componentes.
- Ajuda — resolução de problemas e FAQ.
- Porquê a Lily — e como apoiar o projeto.
Dúvidas pelo caminho? A página de ajuda está cheia de respostas — e se algum passo puder ser mais claro, diga-nos e melhoraremos o tutorial com todo o gosto.