Kosmesis
Components

Action Bar

A floating contextual toolbar (bulk-selection actions, ...). Purely presentational — no Morphos equivalent.

Installation

npx kosmesis add action-bar
pnpm dlx kosmesis add action-bar
yarn dlx kosmesis add action-bar
bunx kosmesis add action-bar

This component builds on other Kosmesis components — install these first (via kosmesis add or this same manual process on their own pages): separator.

Copy and paste the following code into your project.

action-bar.tsx
import { StatelessComponent } from "@praxisjs/core";import { Component } from "@praxisjs/decorators";import type { Children } from "@praxisjs/shared";import { Separator } from "./separator";import { cn } from "@/lib/utils";export interface ActionBarProps {  open?: boolean;  class?: string;  children?: Children;}// Keep mounted and toggle `open` for the enter/exit transition; unmounting skips the exit animation.@Component()export class ActionBar extends StatelessComponent<ActionBarProps> {  render() {    const { open = true, class: cls, children } = this.props;    return (      <div        role="toolbar"        data-slot="action-bar"        data-state={open ? "open" : "closed"}        class="pointer-events-none fixed inset-x-0 bottom-6 z-50 flex justify-center px-4"      >        <div          class={cn(            "pointer-events-auto flex items-center gap-2 rounded-full border bg-popover px-3 py-2 text-popover-foreground shadow-lg transition-all duration-200",            "in-data-[state=closed]:pointer-events-none in-data-[state=closed]:translate-y-2 in-data-[state=closed]:opacity-0",            cls,          )}        >          {children}        </div>      </div>    );  }}export interface ActionBarSlotProps {  class?: string;  children?: Children;}@Component()export class ActionBarText extends StatelessComponent<ActionBarSlotProps> {  render() {    const { class: cls, children } = this.props;    return <span class={cn("px-2 text-sm font-medium whitespace-nowrap", cls)}>{children}</span>;  }}@Component()export class ActionBarSeparator extends StatelessComponent<ActionBarSlotProps> {  render() {    const { class: cls } = this.props;    return <Separator orientation="vertical" class={cn("h-5", cls)} />;  }}

Install the following dependencies:

npm install @praxisjs/css
pnpm add @praxisjs/css
yarn add @praxisjs/css
bun add @praxisjs/css

This component builds on other Kosmesis components — install these first (via kosmesis add or this same manual process on their own pages): separator.

Copy and paste the following code into your project.

action-bar.tsx
import { StatelessComponent } from "@praxisjs/core";import { cx, Stylesheet, Styled, tokenVars } from "@praxisjs/css";import { Component } from "@praxisjs/decorators";import type { Children } from "@praxisjs/shared";import { Separator } from "./separator";import { KosmesisTokens } from "@/lib/kosmesis-theme";const t = tokenVars(KosmesisTokens);class ActionBarStyles extends Stylesheet {  $wrapper = this.css({    pointerEvents: "none",    position: "fixed",    insetInline: "0",    bottom: "1.5rem",    zIndex: 50,    display: "flex",    justifyContent: "center",    padding: "0 1rem",  });  $bar = this.css({    pointerEvents: "auto",    display: "flex",    alignItems: "center",    gap: "0.5rem",    borderRadius: "9999px",    border: `1px solid ${t.border}`,    backgroundColor: t.popover,    color: t.popoverForeground,    padding: "0.5rem 0.75rem",    boxShadow: "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)",    transition: "all 200ms ease",  }).on('[data-state="closed"] &', { pointerEvents: "none", transform: "translateY(0.5rem)", opacity: 0 });  $text = this.css({ padding: "0 0.5rem", fontSize: "0.875rem", fontWeight: 500, whiteSpace: "nowrap" });  $separator = this.css({ height: "1.25rem" });}export interface ActionBarProps {  open?: boolean;  class?: string;  children?: Children;}// Keep mounted and toggle `open` for the enter/exit transition; unmounting skips the exit animation.@Component()export class ActionBar extends StatelessComponent<ActionBarProps> {  @Styled(ActionBarStyles) $s!: ActionBarStyles;  render() {    const { open = true, class: cls, children } = this.props;    return (      <div role="toolbar" data-slot="action-bar" data-state={open ? "open" : "closed"} class={this.$s.$wrapper}>        <div class={cx(this.$s.$bar, cls)}>{children}</div>      </div>    );  }}export interface ActionBarSlotProps {  class?: string;  children?: Children;}@Component()export class ActionBarText extends StatelessComponent<ActionBarSlotProps> {  @Styled(ActionBarStyles) $s!: ActionBarStyles;  render() {    const { class: cls, children } = this.props;    return <span class={cx(this.$s.$text, cls)}>{children}</span>;  }}@Component()export class ActionBarSeparator extends StatelessComponent<ActionBarSlotProps> {  @Styled(ActionBarStyles) $s!: ActionBarStyles;  render() {    const { class: cls } = this.props;    return <Separator orientation="vertical" class={cx(this.$s.$separator, cls)} />;  }}

Examples

About

Purely presentational — no Morphos equivalent. Mount it unconditionally (e.g. alongside a selectable list) and drive open off your own selection state for the enter/exit transition. ActionBarSeparator reuses Separator.

Usage

import { ActionBar, ActionBarSeparator, ActionBarText } from "@/components/ui/action-bar";
import { Button } from "@/components/ui/button";

<ActionBar open={selectedIds.length > 0}>
  <ActionBarText>{selectedIds.length} selected</ActionBarText>
  <ActionBarSeparator />
  <Button size="sm" variant="ghost">Archive</Button>
  <Button size="sm" variant="destructive">Delete</Button>
</ActionBar>

Props

PropTypeDefault
openbooleantrue
classstring

ActionBarText/ActionBarSeparator accept class and (for ActionBarText) children.

On this page