limn
    ↑↓ ChooseEnter OpenEsc Close
    GitHub

    Design system/Design tokens

    Design tokens

    Set the radius scale and animation durations once for the process. Color remains a palette passed to each component.

    Tokens · Radius · MotionFoundation

    Preview

    CodeSource
    use limn::{set_tokens, Motion, Radius, Tokens};
    
    set_tokens(Tokens {
        radius: Radius::DEFAULT.scaled(1.5),
        motion: Motion::DEFAULT,
    });

    Token defaults

    control4 px

    Controls and keycaps

    surface6 px

    Floating surfaces

    card8 px

    Groups in the page

    panel12 px

    Large containers

    hover_ms120 msPointer feedback
    enter_ms140 msArriving surfaces
    exit_ms110 msLeaving surfaces
    move_ms170 msChanges in place

    Logical pixels and milliseconds, from tokens.rs. These tokens apply to the whole process.

    Tokens

    Reference for the values that define the library’s shape and pace, and the one look a host may give every tooltip. For color, see Theming.

    Setting tokens

    use limn::{set_tokens, tokens, Motion, Radius, Tokens};
    
    set_tokens(Tokens {
        radius: Radius::DEFAULT.scaled(1.5),
        motion: Motion::DEFAULT,
        ..Tokens::DEFAULT
    });
    
    let current = tokens(); // read them back
    FunctionEffect
    set_tokens(tokens)Replaces the tokens for the whole process.
    tokens()Returns the tokens in force.

    Elements read the tokens when they are built. An application that rebuilds its tree every frame, which is the normal case, changes on the next frame.

    Tokens are process-wide. They cannot differ between two parts of a window or between two windows.

    Radius

    Corner radii in logical pixels, named for what they round.

    FieldDefaultRounds
    control4Buttons, inputs, menu rows, keycaps, tooltips.
    surface6Surfaces that float: popovers, menus, toasts, the segmented track.
    card8Groups set into the page: alerts, preference groups, activity cards, the calendar.
    panel12The largest containers: dialogs, image previews, the composer.
    ConstructorResult
    Radius::DEFAULTThe table above.
    Radius::SQUAREEvery radius zero.
    Radius::ROUNDControls as pills: 16, 16, 20 and 28.
    radius.scaled(factor)Every radius multiplied by factor. A factor that is negative or not finite leaves it unchanged.

    A radius that is negative or not finite is replaced by its default when the tokens are set.

    A component that lets its caller choose a radius takes a RadiusRole (Control, Surface, Card or Panel), never a number. role.px() reads the radius in force for that role. RadiusRole::Square is always zero: a cell that sits flush inside a row or a bar that paints the surface.

    Not governed by radius tokens

    WhatWhy
    Pills and circles: chips, avatars, the switch, the progress bar, step badgesThese are shapes, not rounded corners. Their radius is half their height.
    Marks inside content: text selections, chart bars, code editor marksThey keep their own 2 to 3 px so they stay legible at any setting.

    Image attachments use the panel radius scaled to keep their nested corners concentric.

    Motion

    Durations in milliseconds, named for the kind of change.

    FieldDefaultApplies to
    hover_ms120A control answering the pointer: hover and press fills.
    enter_ms140A surface arriving: popover, menu, dialog, tooltip, toast, an opening collapsible.
    exit_ms110A surface leaving.
    move_ms170Something travelling or changing state in place: tab indicator, switch thumb, step badge. For things that travel it is the time a spring takes to cover 99% of the distance.
    ConstructorResult
    Motion::DEFAULTThe table above.
    motion.scaled(factor)Every duration multiplied by factor: 2.0 is half speed, 0.5 is double. A factor that is negative or not finite leaves it unchanged.

    A field set to zero makes that kind of change immediate.

    A surface never takes longer to leave than to arrive: its exit lasts exit_ms or its own entrance duration, whichever is shorter.

    Not governed by motion tokens

    WhatControlled by
    Whether anything moves at allUiTree::set_reduced_motion(true). See Animation.
    Spinners, skeleton pulses, text shimmer, the caretFixed periods. Reduced motion stops them.
    ScrollingScrollMotion, per scroll area.
    The crossfade when a popover changes contentFixed.
    The delay before a tooltip appearsFixed at 350 ms.
    Easing curvesFixed.

    Tooltip

    Each palette derives its tooltips’ colors. tooltip: Some(style) paints every tooltip with one TooltipStyle instead, whichever palette its control was built with, such as a music app’s:

    use limn::{set_tokens, Color, Tokens, TooltipStyle};
    
    set_tokens(Tokens {
        tooltip: Some(TooltipStyle {
            background: Color::rgb(40, 40, 40),
            border: Color::TRANSPARENT, // no outline
            keycap: Color::rgb(62, 62, 62),
            text: Color::WHITE,
            muted: Color::rgb(179, 179, 179),
            shadow: Color::rgba(0, 0, 0, 128),
        }),
        ..Tokens::DEFAULT
    });

    None, the default, leaves each palette its own. A tooltip given its own background keeps it.

    Per-component overrides

    Most animated components accept an explicit duration that takes precedence over the token for that one instance:

    Popover::new(anchor, content, open, "dismiss", palette).animation_ms(0) // no entrance
    Tabs::new(items, palette).animation_ms(300)                             // slower indicator
    Element::button("id", "Label").transition_ms(0)                         // instant hover

    Prefer the tokens. An override is for a component that must differ from the rest of the application.

    See also