tuilwindcss¶
This project is inspired by tailwind.css to offers a similar set of classes that can be used directly to construct TUI apps with Textual. It's an experimental project to see if it makes it easier to construct apps.
A collection of available classes are shown in the gallery below.
Tailwind Compatible Classes¶
Background Color¶
This project attemps to mimic the colors that tailwind.css provides. This includes background colors, but text and border colors too.
Overview of all colors.
from textual.app import App, ComposeResult
from textual.widgets import Static
class BackgroundColorDemo(App):
CSS_PATH = "tuilwind.css"
def compose(self) -> ComposeResult:
"""Called to add widgets to the app."""
for i in [100, 200, 300, 400, 500, 600, 700, 800, 900]:
yield Static(f"bg-blue-{i}", classes=f"bg-blue-{i}")
for i in reversed([100, 200, 300, 400, 500, 600, 700, 800, 900]):
yield Static(f"bg-blue-{i}", classes=f"bg-blue-{i}")
if __name__ == "__main__":
app = BackgroundColorDemo()
app.run()
Padding¶
Simple Padding¶
from textual.app import App, ComposeResult
from textual.widgets import Static
class PaddingDemo(App):
CSS_PATH = "tuilwind.css"
def compose(self) -> ComposeResult:
"""Called to add widgets to the app."""
yield Static("p-1", classes="p-1 bg-blue-400")
yield Static("p-2", classes="p-2 bg-blue-500")
yield Static("p-3", classes="p-3 bg-blue-600")
yield Static("p-4", classes="p-4 bg-blue-700")
if __name__ == "__main__":
app = PaddingDemo()
app.run()
Padding Direction¶
You can also be specific in the direction of the padding. So you can specify:
pt-1
to add 1 padding to the toppb-1
to add 1 padding to the bottompl-1
to add 1 padding to the leftpr-1
to add 1 padding to the rightpx-1
to add 1 padding to horizontallypy-1
to add 1 padding to vertically
from textual.app import App, ComposeResult
from textual.widgets import Static
class PaddingDemo(App):
CSS_PATH = "tuilwind.css"
def compose(self) -> ComposeResult:
"""Called to add widgets to the app."""
yield Static("pt-2", classes="pt-2 bg-gray-200 border-round-gray-600 text-gray-700")
yield Static("pb-2", classes="pb-2 bg-gray-300 border-round-gray-600 text-gray-700")
yield Static("pl-2", classes="pl-2 bg-gray-200 border-round-gray-600 text-gray-700")
yield Static("pr-2", classes="pr-2 bg-gray-300 border-round-gray-600 text-gray-700")
yield Static("px-2", classes="px-2 bg-gray-200 border-round-gray-600 text-gray-700")
yield Static("py-2", classes="py-2 bg-gray-300 border-round-gray-600 text-gray-700")
if __name__ == "__main__":
app = PaddingDemo()
app.run()
Margin¶
Simple Margin¶
from textual.app import App, ComposeResult
from textual.widgets import Static
from textual.containers import Vertical
class MarginDemo(App):
CSS_PATH = "tuilwind.css"
def compose(self) -> ComposeResult:
"""Called to add widgets to the app."""
yield Vertical(
Static("m-1 p-1", classes="m-1 p-1 bg-gray-200 border-round-gray-600 text-gray-600"),
Static("m-2 p-1", classes="m-2 p-1 bg-gray-200 border-round-gray-600 text-gray-600"),
Static("m-3 p-2", classes="m-3 p-2 bg-gray-200 border-round-gray-600 text-gray-600"),
classes="bg-gray-300"
)
if __name__ == "__main__":
app = MarginDemo()
app.run()
Margin Direction¶
You can also be specific in the direction of the padding. So you can specify:
mt-1
to add 1 padding to the topmb-1
to add 1 padding to the bottomml-1
to add 1 padding to the leftmr-1
to add 1 padding to the rightmx-1
to add 1 padding to horizontallymy-1
to add 1 padding to vertically
from textual.app import App, ComposeResult
from textual.widgets import Static
from textual.containers import Vertical
class PaddingDemo(App):
CSS_PATH = "tuilwind.css"
def compose(self) -> ComposeResult:
"""Called to add widgets to the app."""
yield Vertical(
Static("mt-2", classes="mt-2 bg-gray-200 border-round-gray-600 text-gray-800"),
Static("mb-2", classes="mb-2 bg-gray-300 border-round-gray-600 text-gray-800"),
Static("ml-2", classes="ml-2 bg-gray-200 border-round-gray-600 text-gray-800"),
Static("mr-2", classes="mr-2 bg-gray-300 border-round-gray-600 text-gray-800"),
Static("mx-2", classes="mx-2 bg-gray-200 border-round-gray-600 text-gray-800"),
Static("my-2", classes="my-2 bg-gray-300 border-round-gray-600 text-gray-800"),
classes="bg-gray-400"
)
if __name__ == "__main__":
app = PaddingDemo()
app.run()
Text¶
Text Color¶
This project attemps to mimic the tet colors that tailwind.css provides.
Overview of all colors.
from textual.app import App, ComposeResult
from textual.widgets import Static
class TextColorDemo(App):
CSS_PATH = "tuilwind.css"
def compose(self) -> ComposeResult:
"""Called to add widgets to the app."""
yield Static("# This is the blue bit!", classes="text-center bold")
for i in [100, 200, 300, 400, 500, 600, 700, 800, 900]:
yield Static("This is some example text.", classes=f"text-blue-{i}")
yield Static("# This is a new section!", classes="text-center bold")
for i in [100, 200, 300, 400, 500, 600, 700, 800, 900]:
yield Static("This is some example text.", classes=f"text-gray-{i}")
if __name__ == "__main__":
app = TextColorDemo()
app.run()
Text Style¶
You can also apply some style to text in Textual. Nothing with text sizes, but the full types are shown below.
from textual.app import App, ComposeResult
from textual.widgets import Static
class TextStyleDemo(App):
CSS_PATH = "tuilwind.css"
def compose(self) -> ComposeResult:
"""Called to add widgets to the app."""
yield Static("This is some text.", classes="")
yield Static("This is some text.", classes="bold")
yield Static("This is some text.", classes="italic")
yield Static("This is some text.", classes="underline")
yield Static("This is some text.", classes="strike")
yield Static("This is some text.", classes="reverse")
if __name__ == "__main__":
app = TextStyleDemo()
app.run()
Text Alignment¶
from textual.app import App, ComposeResult
from textual.widgets import Static
text = """This text is certainly a fair bit long to proove a point.
Oh my yes indeed, it really is a fair bit longer than many other examples!"""
class TextAlignmentDemo(App):
CSS_PATH = "tuilwind.css"
def compose(self) -> ComposeResult:
"""Called to add widgets to the app."""
yield Static(text, classes="p-1 bg-gray-500 text-left")
yield Static(text, classes="p-1 bg-gray-600 text-center")
yield Static(text, classes="p-1 bg-gray-700 text-right")
yield Static(text, classes="p-1 bg-gray-500 text-justify")
yield Static(text, classes="p-1 bg-gray-600 text-start")
yield Static(text, classes="p-1 bg-gray-700 text-end")
if __name__ == "__main__":
app = TextAlignmentDemo()
app.run()
Tailwind Inconsistent Classes¶
Border¶
Borders in CSS allow you to define the border-width seperately from the border-color. Textual doesn't do this, which is why the class names are much longer. That said, this project attemps to mimic the border colors that tailwind.css provides.
Overview of all colors.
Base Border¶
The syntax for a border is <border>-<border-type>-<color>
. The supported border types are:
"ascii","blank","dashed","double","heavy","hidden","hkey","inner","none","outer","round","solid","tall","vkey","wide"
from textual.app import App, ComposeResult
from textual.widgets import Static
class BorderDemo(App):
CSS_PATH = "tuilwind.css"
def compose(self) -> ComposeResult:
"""Called to add widgets to the app."""
yield Static("first", classes="p-2 text-center text-gray-800 bg-gray-100 border-solid-gray-900")
yield Static("second", classes="p-2 text-center text-gray-800 bg-gray-200 border-round-gray-900")
yield Static("third", classes="p-2 text-center text-gray-800 bg-gray-400 border-double-gray-900")
if __name__ == "__main__":
app = BorderDemo()
app.run()
Border Direction¶
You can also be specific in the direction of the border. So you can specify:
border-t-1-<COLOR>
to add a border to the topborder-b-1-<COLOR>
to add a border to the bottomborder-l-1-<COLOR>
to add a border to the leftborder-r-1-<COLOR>
to add a border to the rightborder-x-1-<COLOR>
to add a border to horizontallyborder-y-1-<COLOR>
to add a border to vertically
from textual.app import App, ComposeResult
from textual.widgets import Static
class BorderSidesDemo(App):
CSS_PATH = "tuilwind.css"
def compose(self) -> ComposeResult:
"""Called to add widgets to the app."""
yield Static("t", classes="p-1 text-center text-gray-800 bg-gray-200 border-t-heavy-gray-600")
yield Static("l", classes="p-1 text-center text-gray-800 bg-gray-300 border-l-heavy-gray-600")
yield Static("r", classes="p-1 text-center text-gray-800 bg-gray-200 border-r-heavy-gray-600")
yield Static("b", classes="p-1 text-center text-gray-800 bg-gray-300 border-b-heavy-gray-600")
yield Static("x", classes="p-1 text-center text-gray-800 bg-gray-200 border-x-heavy-gray-600")
yield Static("y", classes="p-1 text-center text-gray-800 bg-gray-300 border-y-heavy-gray-600")
if __name__ == "__main__":
app = BorderSidesDemo()
app.run()
Textual Specific Classes¶
We try to mimic tailwindcss as much as possible. But there are a few places where textual has it's own definitions. For these instances we try to offer classes that follow the spirit of tailwind.
Dock¶
The "dock" is something that is specific to TUI apps. But we felt like we could apply a familiar similar syntax for it.
Dock Left/Right¶
from textual.app import App, ComposeResult
from textual.widgets import Static
class DockDemo(App):
CSS_PATH = "tuilwind.css"
def compose(self) -> ComposeResult:
"""Called to add widgets to the app."""
yield Static("left", classes="dock-left h-full bg-red-600 w-15")
yield Static("right", classes="dock-right h-full bg-yellow-600 w-20")
if __name__ == "__main__":
app = DockDemo()
app.run()
Dock Top/Bottom¶
from textual.app import App, ComposeResult
from textual.widgets import Static
class DockDemo(App):
CSS_PATH = "tuilwind.css"
def compose(self) -> ComposeResult:
"""Called to add widgets to the app."""
yield Static("top", classes="dock-top h-2 bg-green-600 w-full text-center")
yield Static("bottom", classes="dock-bottom h-4 bg-blue-600 w-full text-center")
if __name__ == "__main__":
app = DockDemo()
app.run()