Skip to content

CSS Hooks: A new way to style your React apps

CSS Hooks: A new way to style your React apps

In the world of web development, the management of styles has always been a crucial aspect of building modern and responsive user interfaces. With the rise of CSS in JS libraries like Material UI and Chakra, developers have started creating dynamic and reusable styles using JavaScript; however, the performance implications of these libraries have led to the exploration of alternative solutions. One such solution is CSS Hooks, a library that offers a different approach to managing styles in web applications.

The Problem with CSS in React and CSS in JS Libraries

In React applications, you typically write styles directly with the style prop by applying classes with className, or if you’re using a framework like Material UI or Chakra then you may use the sx attribute, which is more powerful than the baseline attributes. There are some performance concerns in the case of the sx attribute specifically. The framework has to dynamically generate classes with your styles and apply them to the document whenever it is used.

This can become an issue with large and complex applications as your styles will be regularly regenerated on the fly as the user navigates through the application. This has led developers to seek alternative solutions that offer similar flexibility but with better performance.

Introduction to CSS Hooks

CSS Hooks improve upon the aforementioned issues by pre-generating your CSS using configuration hooks. The styles that these hooks generate remain static during the lifetime of the application and are reused wherever possible. CSS variables are utilized under the hood whenever dynamic behavior is needed. By dynamic behavior, I’m referring to advanced CSS features such as pseudo-class selectors and media queries, which are both traditionally unavailable for use with inline styles. CSS Hooks utilize an interesting trick under the hood to accomplish this, which we will now explore.

The Power of CSS Variables and the Fallback Trick

As mentioned before, CSS variables are utilized in order to support using advanced dynamic behavior such as pseudo-selectors in our inline styles. CSS variables are core to something known as the “fallback trick”. The gist of how the fallback trick works is to have the pseudo-selector or media query toggle the state of a variable between initial and an empty invalid value, and then we put the value that we actually want to toggle as the “fallback” value in the reference to the CSS variable inside of the inline style itself.

Changing this fallback value inside of an inline style essentially allows us to control the values used by the pseudo-selector without having to regenerate linked stylesheets as we only have to change the inline style attribute. This is best explained with an example:

<a
  href="https://example.com"
  style="color: var(--focus-true, #6a49ce) var(--focus-false, #3f6ab9)"
>
  Go to example.com
</a>

<style>
  * {
    --focus-false: initial;
    --focus-true: ;
  }

  :focus {
    --focus-false: ;
    --focus-true: initial;
  }
</style>

This plain HTML and CSS code effectively allows us to utilize the focus pseudo-selector on any element that we want using inline styles only. This is what CSS Hooks effectively does in the background when you use dynamic styles. No nasty re-renders and mucking with stylesheets needed!

How to use CSS Hooks

Now that we know how CSS Hooks fundamentally work, let’s try using them. The library itself is much easier to use than the aforementioned example. Installation and usage of CSS Hooks is easy. Firstly, we must install the @css-hooks/react package into a React project with the package manager of your choice (npm, pnpm yarn, etc). Once that’s done, all that’s left is a little bit of configuration.

You have to first use a utility function called createHooks that is exported from the package we just installed. The result of that function returns a couple of variables in an array that can be deconstructed, the first being a stylesheet in the form of a string, and the second being a function.

import { createHooks } from "@css-hooks/react";

export const [hooks, css] = createHooks({});

I recommend putting this in a separate file that can be imported from multiple other places in the project as this is where we will be configuring hooks across the project. We’re exporting both hooks and css, and both are important.

We need to include hooks into the DOM as it contains the styles of the hooks that we’ll be referencing in our components. In your root component you need to add the following <style> tag so that the generated CSS can be used.

import { hooks } from "./css-hooks";

function App() {
  return (
    <>
      <style dangerouslySetInnerHTML={{ __html: hooks }} />

			...
    </>
  );
}

export default App;

How this is done may vary based on the libraries that you are using. After that’s done, you can integrate CSS Hooks into your components while writing inline styles mostly just like you would do normally, with the only change being the addition of an additional call to the css function that we exported earlier:

import { css } from "./css-hooks";

function SomeReactComponent(props) {
	return (
		<button
			style={css({
				padding: 0,
				margin: 0,

				...
			})}
		>
			{props.text}
		</button>
	)
}

Now that the core boilerplate is set up, your components can now utilize CSS Hooks in theory; however we need to actually add some hooks to start with before we can use them, or else we’ll just be limited to basic styles in the same way that React inline styles are.

Make your own hooks

We can define our hooks inside of the css-hooks file that we created earlier, the same one that exports the css helper function that gets CSS Hooks working with our components. Hooks are defined in the options parameters that are currently empty. Defining a simple hook that allows us to define inline hover styles for a component is very easy and can be done as follows:

import { createHooks } from "@css-hooks/react";

export const [hooks, css] = createHooks({
	"&:hover": "&:hover",
});

Although both the key and the value in this example are the same, they both serve different purposes. The key is the name of the hook that we reference when we want to use it, while the value is the spec. The spec is the actual CSS selector that we’re writing. The name can be anything that you want it to be so long as it doesn’t clash with any existing style properties or hooks.

Although making your own hooks may be necessary at times, there is another repository provided by the CSS Hooks authors that adds a way to generate many useful hooks called @css-hooks/recommended. I highly recommend using this library to generate your hooks if at all possible, and the usage is pretty simple. Here’s an example showing how you can use it to generate media queries, color scheme specific styles and pseudo-selectors:

import { createHooks } from "@css-hooks/react";
import { recommended } from "@css-hooks/recommended";

export const [hooks, css] = createHooks(recommended({
  breakpoints: ["500px", "1000px"],
  colorSchemes: ["dark", "light"],
  pseudoClasses: [
    ":hover",
    ":focus",
    ":active",
    ":disabled",
  ]
}));

Then with that done, these can be utilized as follows:

import { css } from "./css-hooks";

export default function Home() {
  return (
    <main
      style={css({ maxWidth: 1200, margin: "0 auto", textAlign: "center" })}
    >
      <h1>CSS Hooks Example</h1>
      <p>Here is an example of CSS Hooks in action!</p>

      <a
        href="https://example.com"
        style={css({
          color: "cornflowerblue",
          "&:hover": { color: "red" },
        })}
      >
        Hover over me to make me red
      </a>
    </main>
  );
}

We can also modify the hooks configuration to add our own hooks in addition to the recommended hooks by using the spread operator:

import { createHooks } from "@css-hooks/react";
import { recommended } from "@css-hooks/recommended";

export const [hooks, css] = createHooks({
  ...recommended({
    breakpoints: ["500px", "1000px"],
    colorSchemes: ["dark", "light"],
    pseudoClasses: [":hover", ":focus", ":active", ":disabled"],
  }),

  // Your own custom hooks can go here.
  customFocusHook: "&:focus",
});

Then that custom hook can be used by simply using its key name:

<a
  href="https://example.com"
  style={css({
    color: "cornflowerblue",
    "&:hover": { color: "red" },
    customFocusHook: { color: "lime" },
  })}
>
  Hover over me to make me red
</a>

Summary

CSS Hooks offers a performant alternative to traditional CSS in JS libraries by leveraging CSS variables and providing a unique approach to managing styles in web applications. By pre-generating the stylesheet based on configured hooks and utilizing CSS Variables for dynamic behavior, developers can create reusable styles without the performance overhead associated with dynamic stylesheet generation.

If you're interested in exploring CSS Hooks further, be sure to check out @CSSHooks for more information. You can also find some of the examples demonstrated here in a working app in our demos repository. Thank you for reading!

This Dot is a consultancy dedicated to guiding companies through their modernization and digital transformation journeys. Specializing in replatforming, modernizing, and launching new initiatives, we stand out by taking true ownership of your engineering projects.

We love helping teams with projects that have missed their deadlines or helping keep your strategic digital initiatives on course. Check out our case studies and our clients that trust us with their engineering.

You might also like

How to Truncate Strings Easily with CSS cover image

How to Truncate Strings Easily with CSS

You'll often need to truncate text when working with user interfaces, especially when displaying content within a limited space. CSS provides a straightforward way to handle this scenario, ensuring that long text strings are cut off gracefully without affecting the overall layout. CSS Truncation Techniques Single-Line Truncation If you want to truncate a single line of text, CSS provides a simple solution. The key properties to use here are overflow, white-space, and text-overflow. ` Explanation of properties: * white-space: nowrap: This ensures the text stays on a single line, preventing wrapping. * overflow: hidden: This hides any content that overflows the container. * text-overflow: ellipsis: This adds the ellipsis (…) at the end of the truncated text. Multi-Line Truncation While truncating a single line of text is common, sometimes you may want to display multiple lines but still cut off the text when it exceeds a certain number of lines. You can use a combination of CSS properties such as -webkit-line-clamp along with the display and overflow properties. ` Live example: Explanation of properties: * display: -webkit-box: This is a legacy flexbox-like display property that works with the -webkit-line-clamp property. * -webkit-line-clamp: Specifies the number of lines to show before truncating. * -webkit-box-orient: vertical: Ensures the box is laid out vertically for proper multi-line truncation. * overflow: hidden: Prevents content overflow. * text-overflow: ellipsis: Adds an ellipsis after the truncated content. Why Use CSS for Text Truncation Over JavaScript Techniques? While it’s possible to truncate text using JavaScript, CSS is often a better choice for this task for several reasons. Let's explore why CSS-based truncation techniques are generally preferred over JavaScript. Performance Efficiency CSS operates directly within the browser's layout engine, meaning it doesn’t require additional processing or event handling as JavaScript does. When using JavaScript to truncate text, the script needs to run on page load (or after DOM manipulation), and sometimes, it needs to listen for events such as window resizing to adjust truncation. This can introduce unnecessary overhead, especially in complex or resource-constrained environments like mobile devices. CSS, on the other hand, is declarative. Once applied, it allows the browser to handle text rendering without any further execution or processing. This leads to faster load times and a smoother user experience. Simplicity and Maintainability CSS solutions are much simpler to implement and maintain than their JavaScript counterparts. All it takes is a few lines of CSS to implement truncation. In contrast, a JavaScript solution would require you to write and maintain a function that manually trims strings, inserts ellipses, and re-adjusts the text whenever the window is resized. Here's the JavaScript Truncation Example to compare the complexity: JavaScript Truncation Example: ` At the example above, we truncated the text to 50 characters which may be 1 line on large screens and 6 lines on mobile and in that case we will need to add more code to truncate it responsively. As you can see, the CSS solution we used earlier is more concise and readable, whereas the JavaScript version is more verbose and requires managing the string length manually. Responsiveness Without Extra Code With CSS, truncation can adapt automatically to different screen sizes and layouts. You can use relative units (like percentages or vw/vh), media queries, or flexbox/grid properties to ensure the text truncates appropriately in various contexts. If you were using JavaScript, you’d need to write additional logic to detect changes in the viewport size and update the truncation manually. This would likely involve adding event listeners for window resize events, which can degrade performance and lead to more complex code. CSS Example for Responsive Truncation: ` To achieve this in JavaScript, you’d need to add more code to handle the width adjustments dynamically, making it more complex to maintain and troubleshoot. Separation of Concerns CSS handles the presentation layer of your website, while JavaScript should focus on dynamic functionality or data manipulation. By keeping truncation logic within your CSS, you're adhering to the principle of separation of concerns, where each layer of your web application has a clear, well-defined role. Using JavaScript for visual tasks like truncation mixes these concerns, making your codebase harder to maintain, debug, and scale. CSS is purpose-built for layout and visual control, and truncation is naturally a part of that domain. Browser Support and Cross-Browser Consistency Modern CSS properties like text-overflow and -webkit-line-clamp are widely supported across all major browsers. This means that CSS solutions for truncation are generally consistent and reliable. JavaScript solutions, on the other hand, may behave differently depending on the browser environment and require additional testing and handling for cross-browser compatibility. While older browsers may not support specific CSS truncation techniques (e.g., multi-line truncation), fallback options (like single-line truncation) can be easily managed through CSS alone. With JavaScript, more complex logic might be required to handle such situations. Reduced Risk of Layout Shifting JavaScript-based text truncation risks causing layout shifting, especially during initial page loads or window resizes. The browser may need to recalculate the layout multiple times, leading to content flashing or jumpy behavior as text truncation is applied. CSS-based truncation is applied as part of the browser’s natural rendering flow, eliminating this risk and ensuring a smoother experience for the user. Conclusion CSS is the optimal solution for truncating text in most cases due to its simplicity, efficiency, and responsiveness. It leverages the power of the browser’s rendering engine, avoids the overhead of JavaScript, and keeps your code clean and maintainable. While JavaScript truncation has its use cases, CSS should always be your go-to solution for truncating strings, especially in static or predictable layouts. If you like this post, check out the other CSS posts on our blog!...

CSS Container Queries, what are they? cover image

CSS Container Queries, what are they?

CSS Container queries, what are they? Intro Media queries have always been crucial to building web applications. They help make our apps more accessible and easier to use and ensure we reach most of our audience. Media queries have been essential in frontend development to create unique user interfaces. But now, there’s something new: Container queries. In this blog post, we’ll explore what Container queries are, how they differ from media queries, and why they’re so amazing. So, let’s get started! Refresh on Media queries Media queries have been available in browsers for a long time, but they didn’t become popular until around 2010 when mobile devices started to take off. Media queries let us add specific styles based on the type of device, like screens or printers. This is especially helpful for creating modern, responsive apps. A simple use of Media queries would be changing, for example, a paragraph's font size when the screen width is less than a specific number. ` In this simple example, when the browser’s viewport width is less or equal to 400px, the font size changes to 8px. Notice how straightforward the syntax is: we start with the keyword @media, followed by the type of device it should apply to. In this case, we use screen so it doesn’t affect users who print the page—if you don’t add anything, then it falls back to the default, which is “all” including both print and screen. Then we specify a media feature, in this case, the width. Container queries Container queries are similar to Media queries. Their main function is to apply styles under certain conditions. The difference is that instead of listening to the viewport of the browser, it listens to a container size. Let’s see this example: In the above layout, we have a layout with a sidebar and three cards as the content. Using Media queries we could listen to the viewport width and change the layout depending on a specific width. Like so: ` That’s acceptable, but it requires us to constantly monitor the layout. For example, if we added another sidebar on the right (really weird, but let’s imagine that this is a typical case), our layout would become more condensed: We would need to change our media queries and adjust their range in this situation. Wouldn’t it be better to check the card container’s width and update its styles based on that? That way, we wouldn’t need to worry about if the layout changes, and that’s precisely what container queries are made for! First, to define the container we are going to listen to, we are going to add a new property to our styles: ` The .container class is the one in which our cards reside. By adding the property `container-type, ' we now define this class as a container we want to listen to. We said inline-size as the value to query based on the inline dimensions of the container because we just want to listen to the element's width. The value of container-type will depend on your use case. If you want to listen to both width and height, then size will be a better fit for you. You can also have normal as your container-type value, which means the element won’t act as a query container at all. This is handy if you need to revert to the default behavior. Next, to define our query, we use the new @container CSS at-rule: ` Notice that it is really similar to how we define our Media queries. Now, if we look at the same screen, we will see the following: This is very powerful because we can now style each component with its own rules without changing the rules based on the layout changes. The @container will affect all the defined containers in the scope; we might not want that. We can define the name of our container to specify that we only want to listen to that in specific: ` We can also have a shorthand to define our container and its name: ` Container query length units Container query lengths are similar to the viewport-percentage length units like vh or vw units, but instead of being relative to the viewport, they are to the dimensions of the query container. We have different units, each relative to different dimensions of the container: - cqw: 1% of a query container's width - cqh: 1% of a query container's height - cqi: 1% of a query container's inline size - cqb: 1% of a query container's block size - cqmin: The smaller value of either cqi or cqb - cqmax: The larger value of either cqi or cqb In our example, we could use them to define the font size of our cards: ` Using these units alone isn’t recommended because they’re percentage-based and can have a value we don’t want. Instead, it’s better to use a dynamic range. Using the max function, we can set 2 values and always pick the highest one. Conclusion Container queries bring a fresh and powerful approach to web design but are not meant to replace Media queries. I think their real power shines when used together. Media queries often require constant adjustments as your layout evolves. Container queries, however, let you style individual components based on their dimensions, making the designs more flexible and easier to manage. Adding a new component or rearranging elements won’t force us to rewrite our media queries. Instead, each component handles its styling, leading to cleaner and more organized code. Please note that, as of writing this blog post, they aren’t compatible with all browsers yet. Take a look at this table from caniuse.com: A good fallback strategy for this, when hitting an unsupported browser would be the use of the @support rule, which allows you to apply styles only if the browser supports the CSS feature. For example: ` Ensure your media queries are good enough to keep everything responsive and user-friendly when the condition is unmet. Thank you for reading! Enjoy the extra flexibility that container queries bring to your web designs. Check out a live demo to see it in action. Happy styling!...

The HTML Dialog Element: Enhancing Accessibility and Ease of Use cover image

The HTML Dialog Element: Enhancing Accessibility and Ease of Use

The HTML Dialog Element: Enhancing Accessibility and Ease of Use Dialogs are a common component added to applications, whether on the web or in native applications. Traditionally there has not been a standard way of implementing these on the web, resulting in many ad-hoc implementations that don’t act consistently across different web applications. Often, commonly expected features are missing from dialogs due to the complexity of implementing them. However, web browsers now offer a standard dialog element. Why use the dialog element? The native dialog element streamlines the implementation of dialogs, modals, and other kinds of non-modal dialogs. It does this by implementing many of the features needed by dialogs for you that are already baked into the browser. This is helpful as it reduces the burden on the developer when making their applications accessible by ensuring that user expectations concerning interaction are met, and it can also potentially simplify the implementation of dialogs in general. Basic usage Adding a dialog using the new tag can be achieved with just a few lines of code. ` However, adding the dialog alone won’t do anything to the page. It will show up only once you call the .showModal() method against it. ` Then if you want to close it you can call the .close() method on the dialog, or press the escape key to close it, just like most other modals work. Also, note how a backdrop appears that darkens the rest of the page and prevents you from interacting with it. Neat! Accessibility and focus management Correctly handling focus is important when making your web applications accessible to all users. Typically you have to move the current focus to the active dialog when showing them, but with the dialog element that’s done for you. By default, the focus will be set on the first focusable element in the dialog. You can optionally change which element receives focus first by setting the autofocus attribute on the element you want the focus to start on, as seen in the previous example where that attribute was added to the close element. Using the .showModal() method to open the dialog also implicitly adds the dialog ARIA role to the dialog element. This helps screen readers understand that a modal has appeared and the screen so it can act accordingly. Adding forms to dialogs Forms can also be added to dialogs, and there’s even a special method value for them. If you add a element with the method set to dialog then the form will have some different behaviors that differ from the standard get and post form methods. First off, no external HTTP request will be made with this new method. What will happen instead is that when the form gets submitted, the returnValue property on the form element will be set to the value of the submit button in the form. So given this example form: ` The form element with the example-form id will have its returnValue set to Submit. In addition to that, the dialog will close immediately after the submit event is done being handled, though not before automatic form validation is done. If this fails then the invalid event will be emitted. You may have already noticed one caveat to all of this. You might not want the form to close automatically when the submit handler is done running. If you perform an asynchronous request with an API or server you may want to wait for a response and show any errors that occur before dismissing the dialog. In this case, you can call event.preventDefault() in the submit event listener like so: ` Once your desired response comes back from the server, you can close it manually by using the .close() method on the dialog. Enhancing the backdrop The backdrop behind the dialog is a mostly translucent gray background by default. However, that backdrop is fully customizable using the ::backdrop pseudo-element. With it, you can set a background-color to any value you want, including gradients, images, etc. You may also want to make clicking the backdrop dismiss the modal, as this is a commonly implemented feature of them. By default, the &lt;dialog> element doesn’t do this for us. There are a couple of changes that we can make to the dialog to get this working. First, an event listener is needed so that we know when the user clicks away from the dialog. ` Alone this event listener looks strange. It appears to dismiss the dialog whenever the dialog is clicked, not the backdrop. That’s the opposite of what we want to do. Unfortunately, you cannot listen for a click event on the backdrop as it is considered to be part of the dialog itself. Adding this event listener by itself will effectively make clicking anywhere on the page dismiss the dialog. To correct for this we need to wrap the contents of the dialog content with another element that will effectively mask the dialog and receive the click instead. A simple element can do! ` Even this isn’t perfect though as the contents of the div may have elements with margins in them that will push the div down, resulting in clicks close to the edges of the dialog to dismiss it. This can be resolved by adding a couple of styles the the wrapping div that will make the margin stay contained within the wrapper element. The dialog element itself also has some default padding that will exacerbate this issue. ` The wrapping div can be made into an inline-block element to contain the margin, and by moving the padding from the parent dialog to the wrapper, clicks made in the padded portions of the dialog will now interact with the wrapper element instead ensuring it won’t be dismissed. Conclusion Using the dialog element offers significant advantages for creating dialogs and modals by simplifying implementation with reasonable default behavior, enhancing accessibility for users that need assistive technologies such as screen readers by using automatic ARIA role assignment, tailored support for form elements, and flexible styling options....

What Sets the Best Autonomous Coding Agents Apart? cover image

What Sets the Best Autonomous Coding Agents Apart?

Must-have Features of Coding Agents Autonomous coding agents are no longer experimental, they are becoming an integral part of modern development workflows, redefining how software is built and maintained. As models become more capable, agents have become easier to produce, leading to an explosion of options with varying depth and utility. Drawing insights from our experience using many agents, let's delve into the features that you'll absolutely want to get the best results. 1. Customizable System Prompts Custom agent modes, or roles, allow engineers to tailor the outputs to the desired results of their task. For instance, an agent can be set to operate in a "planning mode" focused on outlining development steps and gathering requirements, a "coding mode" optimized for generating and testing code, or a "documentation mode" emphasizing clarity and completeness of written artifacts. You might start with the off-the-shelf planning prompt, but you'll quickly want your own tailored version. Regardless of which modes are included out of the box, the ability to customize and extend them is critical. Agents must adapt to your unique workflows and prioritize what's important to your project. Without this flexibility, even well-designed defaults can fall short in real-world use. Engineers have preferences, and projects contain existing work. The best agents offer ways to communicate these preferences and decisions effectively. For example, 'pnpm' instead of 'npm' for package management, requiring the agent to seek root causes rather than offer temporary workarounds, or mandating that tests and linting must pass before a task is marked complete. Rules are a layer of control to accomplish this. Rules reinforce technical standards but also shape agent behavior to reflect project priorities and cultural norms. They inform the agent across contexts, think constraints, preferences, or directives that apply regardless of the task. Rules can encode things like style guidelines, risk tolerances, or communication boundaries. By shaping how the agent reasons and responds, rules ensure consistent alignment with desired outcomes. Roo code is an agent that makes great use of custom modes, and rules are ubiquitous across coding agents. These features form a meta-agent framework that allows engineers to construct the most effective agent for their unique project and workflow details. 2. Usage-based Pricing The best agents provide as much relevant information as possible to the model. They give transparency and control over what information is sent. This allows engineers to leverage their knowledge of the project to improve results. Being liberal with relevant information to the models is more expensive however, it also significantly improves results. The pricing model of some agents prioritizes fixed, predictable costs that include model fees. This creates an incentive to minimize the amount of information sent to the model in order to control costs. To get the most out of these tools, you’ve got to get the most out of models, which typically implies usage-based pricing. 3. Autonomous Workflows The way we accomplish work has phases. For example, creating tests and then making them pass, creating diagrams or plans, or reviewing work before submitting PRs. The best agents have mechanisms to facilitate these phases in an autonomous way. For the best results, each phase should have full use of a context window without watering down the main session's context. This should leverage your custom modes, which excel at each phase of your workflow. 4. Working in the Background The best agents are more effective at producing desired results and thus are able to be more autonomous. As agents become more autonomous, the ability to work in the background or work on multiple tasks at once becomes increasingly necessary to unlock their full potential. Agents that leverage local or cloud containers to perform work independently of IDEs or working copies on an engineer's machine further increase their utility. This allows engineers to focus on drafting plans and reviewing proposed changes, ultimately to work toward managing multiple tasks at once, overseeing their agent-powered workflows as if guiding a team. 5. Integrations with your Tools The Model Context Protocol (MCP) serves as a standardized interface, allowing agents to interact with your tools and data sources. The best agents seamlessly integrate with the platforms that engineers rely on, such as Confluence for documentation, Jira for tasks, and GitHub for source control and pull requests. These integrations ensure the agent can participate meaningfully across the full software development lifecycle. 6. Support for Multiple Model Providers Reliance on a single AI provider can be limiting. Top-tier agents support multiple providers, allowing teams to choose the best models for specific tasks. This flexibility enhances performance, the ability to use the latest and greatest, and also safeguards against potential downtimes or vendor-specific issues. Final Thoughts Selecting the right autonomous coding agent is a strategic decision. By prioritizing the features mentioned, technology leaders can adopt agents that can be tuned for their team's success. Tuning agents to projects and teams takes time, as does configuring the plumbing to integrate well with other systems. However, unlocking massive productivity gains is worth the squeeze. Models will become better and better, and the best agents capitalize on these improvements with little to no added effort. Set your organization and teams up to tap into the power of AI-enhanced engineering, and be more effective and more competitive....

Let's innovate together!

We're ready to be your trusted technical partners in your digital innovation journey.

Whether it's modernization or custom software solutions, our team of experts can guide you through best practices and how to build scalable, performant software that lasts.

Prefer email? hi@thisdot.co