This is a simple React application where I utilize Lexiwind, a custom Tailwind CSS variant, for styling and shadcn/ui for UI components.
- npm i lexiwind or pnpm i
import { Lexiwind, ToolbarPlugin, useToolbar, RichTextPlugin } from "lexiwind";
export const LexiwindEditor = () => {
const [value, setValue] = useState("");
console.log(value)
return (
<>
<Lexiwind value={value} onChange={setValue}>
<div
className={
"lexiwind-border-1 lexiwind-mx-auto lexiwind-max-w-3xl lexiwind-rounded-lg lexiwind-bg-white lexiwind-p-4 lexiwind-shadow-md"
}
>
<ToolbarPlugin>
<CustomToolbar />
</ToolbarPlugin>
<div className="editor-inner">
<RichTextPlugin />
</div>
</div>
</Lexiwind>
</>
);
};
type ToolbarContextType = {
canUndo: boolean;
canRedo: boolean;
isBold: boolean;
isUnderline: boolean;
isItalic: boolean;
isStrikethrough: boolean;
undoHandler: () => void;
redoHandler: () => void;
boldHandler: () => void;
italicHandler: () => void;
underlineHandler: () => void;
strikethroughHandler: () => void;
alignLeftHandler: () => void;
alignCenterHandler: () => void;
alignRightHandler: () => void;
alignJustifyHandler: () => void;
};
"use client";
import { useState, useEffect } from "react";
import { Lexiwind,useToolbar } from "lexiwind";
import { Button } from "./ui/Button";
const CustomToolbar = () => {
const toolbar = useToolbar();
return (
<div className="lexiwind-flex lexiwind-flex-wrap lexiwind-gap-3 lexiwind-p-1">
<Button disabled={!toolbar.canUndo} onClick={toolbar.undoHandler}>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M9 14 4 9l5-5" />
<path d="M4 9h10.5a5.5 5.5 0 0 1 5.5 5.5v0a5.5 5.5 0 0 1-5.5 5.5H11" />
</svg>
</Button>
<Button disabled={!toolbar.canRedo} onClick={toolbar.redoHandler}>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="m15 14 5-5-5-5" />
<path d="M20 9H9.5A5.5 5.5 0 0 0 4 14.5v0A5.5 5.5 0 0 0 9.5 20H13" />
</svg>
</Button>
<Button
onClick={toolbar.boldHandler}
variant={toolbar.isBold ? "active" : "default"}
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M6 12h9a4 4 0 0 1 0 8H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h7a4 4 0 0 1 0 8" />
</svg>
</Button>
<Button
onClick={toolbar.italicHandler}
variant={toolbar.isItalic ? "active" : "default"}
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<line x1="19" x2="10" y1="4" y2="4" />
<line x1="14" x2="5" y1="20" y2="20" />
<line x1="15" x2="9" y1="4" y2="20" />
</svg>
</Button>
<Button
onClick={toolbar.underlineHandler}
variant={toolbar.isUnderline ? "active" : "default"}
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M6 4v6a6 6 0 0 0 12 0V4" />
<line x1="4" x2="20" y1="20" y2="20" />
</svg>
</Button>
<Button
onClick={toolbar.strikethroughHandler}
variant={toolbar.isStrikethrough ? "active" : "default"}
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M16 4H9a3 3 0 0 0-2.83 4" />
<path d="M14 12a4 4 0 0 1 0 8H6" />
<line x1="4" x2="20" y1="12" y2="12" />
</svg>
</Button>
<Button onClick={toolbar.alignLeftHandler}>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<line x1="21" x2="3" y1="6" y2="6" />
<line x1="15" x2="3" y1="12" y2="12" />
<line x1="17" x2="3" y1="18" y2="18" />
</svg>
</Button>
<Button onClick={toolbar.alignCenterHandler}>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<line x1="21" x2="3" y1="6" y2="6" />
<line x1="17" x2="7" y1="12" y2="12" />
<line x1="19" x2="5" y1="18" y2="18" />
</svg>
</Button>
<Button onClick={toolbar.alignRightHandler}>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<line x1="21" x2="3" y1="6" y2="6" />
<line x1="21" x2="9" y1="12" y2="12" />
<line x1="21" x2="7" y1="18" y2="18" />
</svg>
</Button>
<Button onClick={toolbar.alignJustifyHandler}>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<line x1="3" x2="21" y1="6" y2="6" />
<line x1="3" x2="21" y1="12" y2="12" />
<line x1="3" x2="21" y1="18" y2="18" />
</svg>
</Button>
</div>
);
};
// CustomToolbar Component
const CustomToolbar = () => {
const toolbar = useToolbar();
return (
<div className="some-wrapper-toolbar-class">
<Button disabled={!toolbar.canUndo} onClick={toolbar.undoHandler}>
...
</Button>
<Button disabled={!toolbar.canRedo} onClick={toolbar.redoHandler}>
...
</Button>
...
</div>
);
};
- React.js
- tailwind
- shadcn/ui
- lexical
This project is licensed under the MIT License.